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.



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

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



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

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
58
# File 'lib/dynamic_class.rb', line 31

def add_methods!(key)
  class_exec do
    mutex.synchronize do
      attr_writer key unless method_defined?("#{key}=")
      attr_reader key unless method_defined?("#{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 "        def to_h\n          {\n            \#{\n              attributes.map { |attribute|\n                \"\#{attribute.inspect} => \#{attribute}\"\n              }.join(\",\\n\")\n            }\n          }\n        end\n      RUBY\n    end\n  end\nend\n"

.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 "    def to_h\n      {}\n    end\n  RUBY\nend\n"

.mutexObject



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

def mutex
  @mutex ||= Mutex.new
end

Instance Method Details

#==(other) ⇒ Object



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

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

#[](key) ⇒ Object



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

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

#[]=(key, value) ⇒ Object



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

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



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

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

#each_pairObject



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

def each_pair
  return to_enum(__method__) { self.class.attributes.size } unless block_given?
  to_h.each_pair do |key, value|
    yield key, value
  end
end

#eql?(other) ⇒ Boolean

Returns:

  • (Boolean)


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

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

#hashObject



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

def hash
  to_h.hash
end

#to_hObject



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

def to_h
  {}
end