Module: Finest::Helper

Included in:
Builder, Struct
Defined in:
lib/finest/builder.rb

Overview

Finest Builder

Instance Method Summary collapse

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(name, *args) ⇒ Object



94
95
96
# File 'lib/finest/builder.rb', line 94

def method_missing(name, *args)
  accessor_builder(name.to_s.gsub(/=$/, ''), args[0]) if name.to_s =~ /=$/
end

Instance Method Details

#accessor_builder(key, val) ⇒ Object

Builds an instance variable as well as its class method accessors from a key value pair.



47
48
49
50
51
# File 'lib/finest/builder.rb', line 47

def accessor_builder(key, val)
  instance_variable_set("@#{key}", val)
  self.class.send(:define_method, key.to_s, proc { instance_variable_get("@#{key}") })
  self.class.send(:define_method, "#{key}=", proc { |val| instance_variable_set("@#{key}", val) })
end

#attribute_from_inner_key(elem, attr, in_key = nil) ⇒ Object



102
103
104
# File 'lib/finest/builder.rb', line 102

def attribute_from_inner_key(elem, attr, in_key = nil)
  { attr.to_sym => nested_hash_value(elem, in_key&.present? ? in_key : attr.to_s) }
end

#build_by_keys(json = {}, keys = []) {|_self| ... } ⇒ Object

Parses a given json structure looking for specific keys inside the structure if passed

The result it’s stored on a instance variable called to_h and accessible through accessor with same name as well as it created a instance method for every key. All methods are created using the snake case approach.

e = MyObjectBuilder.new({"client"=> {"idSA"=>1,"id"=>3434, "ManagementType"=>"iOSUnsupervised"}})

Result:

e.client.to_h[:id_sa]
e.client.id_sa

Any key value less than three characters will just be down cased.

e.client.to_h[:id]
e.client.id

Yields:

  • (_self)

Yield Parameters:

Raises:

  • (ArgumentError)


32
33
34
35
36
37
38
39
40
41
42
43
44
# File 'lib/finest/builder.rb', line 32

def build_by_keys(json = {}, keys = [])

  keys = keys.empty? ? json.keys : keys
  raise ArgumentError unless keys&.respond_to?(:each)

  json.transform_keys!(&:to_s)
  keys&.reject! { |key| key.end_with?('=') }
  keys&.each do |key|
    send("#{key.to_s.snake_case}=", nested_hash_value(json, key.to_s))
  end
  yield self if block_given?
  self
end

#nested_hash_value(obj, key) ⇒ Object

Goes through a complex Hash nest and gets the value of a passed key. First wil check whether the object has the key? method, which will mean it’s a Hash and also if the Hash the method parameter key

if obj.respond_to?(:key?) && obj.key?(key)

If result object is a hash itself, will call constructor method to parse this hash first.

if obj[key].is_a?(Hash)
         self.class.new(obj[key])

If it’s an array, will call the constructor method for each element of the array, mapping the result.

elsif (obj[key].is_a?(Array))

As mentioned before, this methods looks for the key passed as parameter, if it’s not found, will go through the nested hash looking for the key, calling itself recursively.

This way we can look for specific keys inside a complex hash structure and ignore the rest. The result of this action will be an object with the keys found and their values. If eventually the keys was not found, it will assign nil to the instance variable.



74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# File 'lib/finest/builder.rb', line 74

def nested_hash_value(obj, key)
  if obj.respond_to?(:key?) && obj.key?(key)
    if obj[key].is_a?(Hash)
      self.class.new(obj[key])
    elsif (obj[key].is_a?(Array))
      obj[key].map! do |a|
        a.respond_to?(:key?) ? self.class.new(a) : a
      end
    else
      obj[key]
    end
  elsif obj.respond_to?(:each)
    r = nil
    obj.find do |*a|
      r = nested_hash_value(a.last, key)
    end
    r
  end
end

#respond_to_missing?(method_name, include_private = false) ⇒ Boolean

Returns:

  • (Boolean)


98
99
100
# File 'lib/finest/builder.rb', line 98

def respond_to_missing?(method_name, include_private = false)
  method_name.to_s.start_with?('to_') || super
end