0

I've got response which hash and array of hashes:

"id"=>67547,
 "description"=>"project",
 "actors"=>
  [
    {"id"=>123,
    "displayName"=>"John Doe",
    "type"=>"atlassian-user-role-actor",
    "name"=>"john.doe",
    "actorUser"=>{"accountId"=>"some_id"}},
   {"id"=>456,
     "displayName"=>"Chris Sth",
     "type"=>"atlassian-user-role-actor",
     "name"=>"chris.sth",
     "actorUser"=>{"accountId"=>"some_id"}},
   {"id"=>789,
     "displayName"=>"Testing Name",
     "type"=>"atlassian-user-role-actor",
     "name"=>"testing.name",
     "actorUser"=>{"accountId"=>"some_id"}},
  ]

What I need is to pull the name for each hash['actors'] and convert it to the email address. The thing is I need to skip names which are defined as EXCLUDED_NAMES

EXCLUDED_NAMES = %w[
  chris.sth
  removed1258986304
  john.doe
  other.names
].freeze

private_constant :DEFAULT_EXCLUDED_NAMES

I was trying to something like below but still get all names:

def setup_email
  dev_role['actors'].map do |user|
    if user.include?(EXCLUDED_NAMES)
      user.delete
    else
      "#{user['name']}@example.com"
    end
  end
end
mr_muscle
  • 2,536
  • 18
  • 61
  • All of the answers (except for one part of @3limin4t0r's answer) contains `EXCLUDED_NAMES.include?(user["name"])`. If `EXCLUDED_NAMES.include?(user["name"])` is large you can speed thing up by working with a set, for which lookup times are fast, comparable with key lookups in hashes: `require 'set'; ex = EXCLUDED_NAMES.to_set`, then replace `EXCLUDED_NAMES` in the code with `ex`. – Cary Swoveland Feb 04 '20 at 18:55

4 Answers4

2

You can get an array of valid emails with:

emails = dev_role['actors'].map do |user|
  "#{user['name']}@example.com" unless EXCLUDED_NAMES.include?(user['name'])
end

Array will only contain 'testing.name@example.com'

romnoks
  • 131
  • 7
  • *"Array will only contain 'testing.name@example.com'"* and `nil` values – 3limin4t0r Feb 04 '20 at 14:35
  • A small suggestion: format you answers so that readers are not required to scroll horizontally to read them (here, perhaps break the penultimate line after `unless`). Also, `emails =` is an unneeded distraction. – Cary Swoveland Feb 04 '20 at 19:10
1

If dev_role['actors'] is this:

  [
    {"id"=>123,
    "displayName"=>"John Doe",
    "type"=>"atlassian-user-role-actor",
    "name"=>"john.doe",
    "actorUser"=>{"accountId"=>"some_id"}},
   {"id"=>456,
     "displayName"=>"Chris Sth",
     "type"=>"atlassian-user-role-actor",
     "name"=>"chris.sth",
     "actorUser"=>{"accountId"=>"some_id"}},
   {"id"=>789,
     "displayName"=>"Testing Name",
     "type"=>"atlassian-user-role-actor",
     "name"=>"testing.name",
     "actorUser"=>{"accountId"=>"some_id"}},
  ]

then it is certain that user in each block would be a Hash object:

{
  "id"=>123,
  "displayName"=>"John Doe",
  "type"=>"atlassian-user-role-actor",
  "name"=>"john.doe",
  "actorUser"=>{"accountId"=>"some_id"}
}

So, doing user["name"], should produce: "john.doe".

Now, that we have an exclusion list EXCLUDED_NAMES we could use include? like so on it:

EXCLUDED_NAMES.include?(user["name"])
=> # true if the name is in the EXCLUDED_NAMES

So, all you need is a small change in your code to fix the condition:

def setup_email
  dev_role['actors'].map do |user|
    if EXCLUDED_NAMES.include?(user["name"])
      user.delete
    else
      "#{user['name']}@example.com"
    end
  end
end

There is one problem though, the user.delete would not work as it expects an argument that is supposed to be a key to the hash object.

This can be fixed through by using reject or select(changing to reject as it reads better):

def setup_email
  dev_role['actors'].reject do |user|
    EXCLUDED_NAMES.include?(user["name"])
  end.map{ |user| user["name"] }
end

The nature of the method seems to be returning an array/list, so I would insist that the name of such methods should be plural: setup_emails.

Surya
  • 15,703
  • 3
  • 51
  • 74
  • Thanks for the clarification, one thing - rubocop suggested me to use `reject` instead of `select` – mr_muscle Feb 04 '20 at 14:54
  • eaither is fine. – Surya Feb 04 '20 at 17:13
  • ...but `reject` reads better because if avoids the negation and also saves one operation. – Cary Swoveland Feb 04 '20 at 18:19
  • Your explanation is confusing. You say, "So, all you need is a small change in your code.", followed by a block of code that modifies code given by the OP, presumably containing the "small change" needed to correct it. You then go on to say, however, that the code you just gave does not in fact correct it: "I am not sure if `user.delete` would work as it expects an argument which is supposed to be a key." You are *not* "not sure"; you know very well that `user.delete` will raise an exception, for the reason you gave, so say it. – Cary Swoveland Feb 04 '20 at 18:43
  • "but `reject`..." - yes you're right, I meant both works. The code change to fix the condition is small, of course, the delete was just not gonna work so had to point it out separately - which was not related to things mentioned in the post. Updated the post by removing not sure part if that's the concern? – Surya Feb 05 '20 at 04:58
0

I'd create a lookup hash based upon the the actor name. Then retrieve the values that are not in EXCLUDED_NAMES.

When actors can contain duplicate names:

actors = dev_role['actors'].group_by { |actor| actor['name'] }
actors = actors.values_at(*actors.keys - EXCLUDED_NAMES).flatten(1)

When actors can't contain duplicate names:

actors = dev_role['actors'].to_h { |actor| [actor['name'], actor] }
actors = actors.values_at(*actors.keys - EXCLUDED_NAMES)

Then:

emails = actors.map { |actor| "#{actor['name']}@example.com" }

You could also solve this with an Array#reject/Array#map combination:

emails = dev_role['actors']
         .reject { |actor| EXCLUDED_NAMES.include?(actor['name']) }
         .map { |actor| "#{actor['name']}@example.com" }

The above might be slower when using a large EXCLUDED_NAMES array.

3limin4t0r
  • 19,353
  • 2
  • 31
  • 52
0
dev_role=dev_role.to_hash
actors=dev_role["actors"]
for each_actor in actors
    if EXCLUDED_NAMES.include?(each_actor["name"])==false
        p "#{each_actor['name']}@example.com"
    end
end