Pregunta

I have some ruby code that gets a json from Jenkins that contains an array of n items. The item I want has a key called "lastBuiltRevision"

I know I can loop through the array like so

actions.each do |action| 
    if action["lastBuiltRevision"]
        lastSuccessfulRev = action["lastBuiltRevision"]["SHA1"]
        break
    end
end

but that feels very clunky and devoid of the magic that I usually feel when working with ruby.

I have only been tinkering with it for roughly a week now, and I feel that I may be missing something to make this easier/faster.

Is there such a thing? or is manual iteration all I can do?

I am kind of hoping for something like

lastSuccessfulRev = action.match("lastBuildRevision/SHA1")
¿Fue útil?

Solución

Using Enumerable#find:

actions = [
  {'dummy' => true },
  {'dummy' => true },
  {'dummy' => true },
  {'lastBuiltRevision' => { "SHA1" => "123abc" }},
  {'dummy' => true },
]
actions.find { |h|
  h.has_key? 'lastBuiltRevision'
}['lastBuiltRevision']['SHA1']
# => "123abc"

UPDATE

Above code will throw NoMethodError if there's no matched item. Use follow code if you don't want get an exception.

rev = actions.find { |h| h.has_key? 'lastBuiltRevision' }
rev = rev['lastBuiltRevision']['SHA1'] if rev

Otros consejos

Here's another way to do it, making use of the form of Enumerable#find that takes a parameter ifnone which is called, and its return value returned, if find's block never evaluates true.

I assume the method is to return nil if either key is not found.

Code

def look_for(actions, k1, k2)
  actions.find(->{{k1=>{}}}) { |e| e.key?(k1) }[k1][k2]
end

Examples

actions = [{ 'dog'=>'woof' }, { 'lastBuiltRevision'=>{ 'SHA1'=> 2 } }]

look_for(actions, 'lastBuiltRevision', 'SHA1') #=> 2
look_for(actions, 'cat, 'SHA1')                #=> nil
look_for(actions, 'lastBuiltRevision', 'cat')  #=> nil

Explanation

I've made find's ifnone parameter the lambda:

l = ->{{k1=>{}}}

so that:

k1 = "cats"
h  = l.call   #=> {"cats"=>{}}
h[k1]['SHA1'] #=> {}['SHA1']
              #=> nil

Try:

action.map { |a| a["lastBuiltRevision"] }.compact.map { |lb| lb["SHA1"] }.first
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top