Class: DynamicClass::Class

Inherits:
Object
  • Object
show all
Defined in:
lib/dynamic_class.rb

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(attributes = {}) ⇒ Class

Returns a new instance of Class.



60
61
62
63
64
# File 'lib/dynamic_class.rb', line 60

def initialize(attributes = {})
  attributes.each_pair do |key, value|
    send(:"#{key}=", value)
  end
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(mid, *args) ⇒ Object



87
88
89
90
91
92
93
94
95
96
97
98
99
# File 'lib/dynamic_class.rb', line 87

def method_missing(mid, *args)
  len = args.length
  if mname = mid[/.*(?==\z)/m]
    if len != 1
      raise ArgumentError, "wrong number of arguments (#{len} for 1)", caller(1)
    end
    self[mname] = args.first
  elsif len == 0
    self[mid]
  else
    raise ArgumentError, "wrong number of arguments (#{len} for 0)", caller(1)
  end
end

Class Method Details

.add_methods!(key) ⇒ Object



31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# File 'lib/dynamic_class.rb', line 31

def add_methods!(key)
  class_exec do
    mutex.synchronize do
      attr_accessor key
      attributes << key

      # I'm pretty sure this is safe, because attempting to add an attribute
      # that isn't a valid instance variable name will raise an error. Please
      # contact the maintainer if you find a situation where this could be a
      # security problem.
      #
      # The reason to use class_eval here is because, based on benchmarking,
      # this defines the fastest version of #to_h possible.
      class_eval <<-RUBY
        def to_h
          {
            #{
              attributes.map { |attribute|
                "#{attribute.inspect} => #{attribute}"
              }.join(",\n")
            }
          }
        end
      RUBY
    end
  end
end

.attributesObject



13
14
15
# File 'lib/dynamic_class.rb', line 13

def attributes
  @attributes ||= Set.new
end

.inherited(subclass) ⇒ Object

Always revert to original #to_h in case the parent class has already redefined #to_h.



19
20
21
22
23
24
25
# File 'lib/dynamic_class.rb', line 19

def inherited(subclass)
  subclass.class_eval <<-RUBY
    def to_h
      {}
    end
  RUBY
end

.mutexObject



27
28
29
# File 'lib/dynamic_class.rb', line 27

def mutex
  @mutex ||= Mutex.new
end

Instance Method Details

#==(other) ⇒ Object



105
106
107
# File 'lib/dynamic_class.rb', line 105

def ==(other)
  other.is_a?(self.class) && to_h == other.to_h
end

#[](key) ⇒ Object



76
77
78
# File 'lib/dynamic_class.rb', line 76

def [](key)
  instance_variable_get(:"@#{key}")
end

#[]=(key, value) ⇒ Object



70
71
72
73
74
# File 'lib/dynamic_class.rb', line 70

def []=(key, value)
  key = key.to_sym
  instance_variable_set(:"@#{key}", value)
  self.class.add_methods!(key) unless self.class.attributes.include?(key)
end

#delete_field(key) ⇒ Object



101
102
103
# File 'lib/dynamic_class.rb', line 101

def delete_field(key)
  instance_variable_set(:"@#{key}", nil)
end

#each_pairObject



80
81
82
83
84
85
# File 'lib/dynamic_class.rb', line 80

def each_pair
  return to_enum(__method__) { self.class.attributes.size } unless block_given?
  self.class.attributes.map do |attribute|
    yield(attribute, instance_variable_get(:"@#{attribute}"))
  end
end

#eql?(other) ⇒ Boolean

Returns:

  • (Boolean)


109
110
111
# File 'lib/dynamic_class.rb', line 109

def eql?(other)
  other.is_a?(self.class) && to_h.eql?(other.to_h)
end

#hashObject



113
114
115
# File 'lib/dynamic_class.rb', line 113

def hash
  to_h.hash
end

#to_hObject



66
67
68
# File 'lib/dynamic_class.rb', line 66

def to_h
  {}
end