Module: Attribution::ClassMethods

Defined in:
lib/attribution.rb

Instance Method Summary collapse

Instance Method Details

#add_association(name, type, metadata = {}) ⇒ Object

Defines an association

Parameters:

  • name (String)

    The name of the association

  • type (Symbol)

    The type of the association

  • metadata (Hash{Symbol => Object}) (defaults to: {})

    The metadata for the association



239
240
241
# File 'lib/attribution.rb', line 239

def add_association(name, type, ={})
  associations << ( || {}).merge(:name => name.to_sym, :type => type.to_sym)
end

#add_attribute(name, type, metadata = {}) ⇒ Object

Defines an attribute

Parameters:

  • name (String)

    The name of the attribute

  • type (Symbol)

    The type of the attribute

  • metadata (Hash{Symbol => Object}) (defaults to: {})

    The metadata for the attribute



80
81
82
83
# File 'lib/attribution.rb', line 80

def add_attribute(name, type, ={})
  attr_reader name
  attributes << ( || {}).merge(:name => name.to_sym, :type => type.to_sym)
end

#array(attr, metadata = {}) ⇒ Object

Defines an array attribute

Parameters:

  • attr (Symbol)

    The name of the attribute

  • metadata (Hash{Symbol => Object}) (defaults to: {})

    The metadata for the attribute



204
205
206
207
208
209
# File 'lib/attribution.rb', line 204

def array(attr, ={})
  add_attribute(attr, :array, )
  define_method("#{attr}=") do |arg|
    instance_variable_set("@#{attr}", Array(arg))
  end
end

#associationsArray<Hash>

Returns The associations for this class.

Returns:

  • (Array<Hash>)

    The associations for this class



226
227
228
229
230
231
232
# File 'lib/attribution.rb', line 226

def associations
  @associations ||= if superclass && superclass.respond_to?(:associations)
    superclass.associations.dup
  else
    []
  end
end

#attribute_namesArray<Symbol>

Returns The names of the attributes in the order in which they were defined.

Returns:

  • (Array<Symbol>)

    The names of the attributes in the order in which they were defined



69
70
71
# File 'lib/attribution.rb', line 69

def attribute_names
  @attribute_names ||= attributes.map{|a| a[:name] }
end

#attributesHash{Symbol => Object}

Returns Each attribute name, type and any related metadata in the order in which they were defined.

Returns:

  • (Hash{Symbol => Object})

    Each attribute name, type and any related metadata in the order in which they were defined



59
60
61
62
63
64
65
# File 'lib/attribution.rb', line 59

def attributes
  @attributes ||= if superclass && superclass.respond_to?(:attributes)
    superclass.attributes.dup
  else
    []
  end
end

#autoload_associations(autoload_associations) ⇒ Object

Parameters:

  • autoload_associations (Boolean)

    Enable/Disable autoloading of associations for this class and all subclasses.



245
246
247
# File 'lib/attribution.rb', line 245

def autoload_associations(autoload_associations)
  @autoload_associations = autoload_associations
end

#autoload_associations?Boolean

Returns autoload_associations Whether or not this will autoload associations.

Returns:

  • (Boolean)

    autoload_associations Whether or not this will autoload associations.



251
252
253
254
255
256
257
258
259
# File 'lib/attribution.rb', line 251

def autoload_associations?
  if defined? @autoload_associations
    @autoload_associations
  elsif superclass.respond_to?(:autoload_associations?)
    superclass.autoload_associations?
  else
    true
  end
end

#belongs_to(association_name, metadata = {}) ⇒ Object

Association macros

Defines an association that is a reference to another Attribution class.

Parameters:

  • association_name (Symbol)

    The name of the association

  • metadata (Hash) (defaults to: {})

    Extra information about the association.

Options Hash (metadata):

  • :class_name (String)

    Class of the association, defaults to a class name based on the association name



269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
# File 'lib/attribution.rb', line 269

def belongs_to(association_name, ={})
  # foo_id
  id_getter = "#{association_name}_id".to_sym
  add_attribute(id_getter, :integer, )
  add_association association_name, :belongs_to, 
  association_class_name = .try(:fetch, :class_name, [name.split('::')[0..-2].join('::'), association_name.to_s.classify].reject(&:blank?).join('::'))

  define_method(id_getter) do
    ivar = "@#{id_getter}"
    if instance_variable_defined?(ivar)
      instance_variable_get(ivar)
    else
      if obj = send(association_name)
        instance_variable_set(ivar, obj.id)
      else
        instance_variable_set(ivar, nil)
      end
    end
  end

  # foo_id=
  define_method("#{id_getter}=") do |arg|
    instance_variable_set("@#{id_getter}", arg.to_i)
  end

  # foo
  define_method(association_name) do
    if instance_variable_defined?("@#{association_name}")
      instance_variable_get("@#{association_name}")
    elsif id = instance_variable_get("@#{association_name}_id")
      association_class = association_class_name.constantize

      if self.class.autoload_associations? && association_class.respond_to?(:find)
        instance_variable_set("@#{association_name}", association_class.find(id))
      end
    else
      instance_variable_set("@#{association_name}", nil)
    end
  end

  # foo=
  define_method("#{association_name}=") do |arg|
    association_class = association_class_name.constantize

    if instance_variable_defined?("@#{association_name}_id")
      remove_instance_variable("@#{association_name}_id")
    end
    instance_variable_set("@#{association_name}", association_class.cast(arg))
  end
end

#boolean(attr, metadata = {}) ⇒ Object

Defines a boolean attribute

Parameters:

  • attr (Symbol)

    The name of the attribute

  • metadata (Hash{Symbol => Object}) (defaults to: {})

    The metadata for the attribute



100
101
102
103
104
105
106
107
108
109
110
111
112
# File 'lib/attribution.rb', line 100

def boolean(attr, ={})
  add_attribute(attr, :boolean, )
  define_method("#{attr}=") do |arg|
    v = case arg
    when String then BOOLEAN_TRUE_STRINGS.include?(arg.downcase)
    when Numeric then arg == 1
    when nil then nil
    else !!arg
    end
    instance_variable_set("@#{attr}", v)
  end
  alias_method "#{attr}?", attr
end

#cast(obj) ⇒ Attribution

Returns An instance of this class.

Parameters:

  • obj (Hash, Attribution)

    The Hash or Object to convert to an instance of this class

Returns:



49
50
51
52
53
54
55
# File 'lib/attribution.rb', line 49

def cast(obj)
  case obj
  when Hash then new(obj)
  when self then obj
  else raise ArgumentError.new("can't convert #{obj.class} to #{name}")
  end
end

#date(attr, metadata = {}) ⇒ Object

Defines a date attribute

Parameters:

  • attr (Symbol)

    The name of the attribute

  • metadata (Hash{Symbol => Object}) (defaults to: {})

    The metadata for the attribute



151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
# File 'lib/attribution.rb', line 151

def date(attr, ={})
  add_attribute(attr, :date, )
  define_method("#{attr}=") do |arg|
    v = case arg
    when Date then arg
    when Time, DateTime then arg.to_date
    when String then Date.parse(arg)
    when Hash
      args = Util.extract_values(arg, :year, :month, :day)
      args.present? ? Date.new(*args.map(&:to_i)) : nil
    when nil then nil
    else raise ArgumentError.new("can't convert #{arg.class} to Date")
    end
    instance_variable_set("@#{attr}", v)
  end
end

#decimal(attr, metadata = {}) ⇒ Object

Defines a decimal attribute

Parameters:

  • attr (Symbol)

    The name of the attribute

  • metadata (Hash{Symbol => Object}) (defaults to: {})

    The metadata for the attribute



140
141
142
143
144
145
# File 'lib/attribution.rb', line 140

def decimal(attr, ={})
  add_attribute(attr, :decimal, )
  define_method("#{attr}=") do |arg|
    instance_variable_set("@#{attr}", arg.nil? ? nil : BigDecimal.new(arg.to_s))
  end
end

#float(attr, metadata = {}) ⇒ Object

Defines a float attribute

Parameters:

  • attr (Symbol)

    The name of the attribute

  • metadata (Hash{Symbol => Object}) (defaults to: {})

    The metadata for the attribute



129
130
131
132
133
134
# File 'lib/attribution.rb', line 129

def float(attr, ={})
  add_attribute(attr, :float, )
  define_method("#{attr}=") do |arg|
    instance_variable_set("@#{attr}", arg.nil? ? nil : arg.to_f)
  end
end

#has_many(association_name, metadata = {}) ⇒ Object

Defines an association that is a reference to an Array of another Attribution class.

Parameters:

  • association_name (Symbol)

    The name of the association

  • metadata (Hash) (defaults to: {})

    Extra information about the association.

Options Hash (metadata):

  • :class_name (String)

    Class of the association, defaults to a class name based on the association name



326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
# File 'lib/attribution.rb', line 326

def has_many(association_name, ={})

  add_association association_name, :has_many, 

  association_class_name = .try(:fetch, :class_name, [name.split('::')[0..-2].join('::'), association_name.to_s.singularize.classify].reject(&:blank?).join('::'))

  # foos
  define_method(association_name) do |*query|
    association_class = association_class_name.constantize

    # TODO: Support a more generic version of lazy-loading
    if query.empty? # Ex: Books.all, so we want to cache it.
      ivar = "@#{association_name}"
      if instance_variable_defined?(ivar)
        instance_variable_get(ivar)
      elsif self.class.autoload_associations? && association_class.respond_to?(:all)
        instance_variable_set(ivar, Array(association_class.all("#{self.class.name.underscore}_id" => id)))
      end
    else # Ex: Book.all(:name => "The..."), so we do not want to cache it
      if self.class.autoload_associations? && association_class.respond_to?(:all)
        Array(association_class.all({"#{self.class.name.demodulize.underscore}_id" => id}.merge(query.first)))
      end
    end
  end

  # foos=
  define_method("#{association_name}=") do |arg|
    association_class = association_class_name.constantize

    attr_name = self.class.name.demodulize.underscore
    objs = (arg.is_a?(Hash) ? arg.values : Array(arg)).map do |obj|
      o = association_class.cast(obj)

      if o.respond_to?("#{attr_name}=")
        o.send("#{attr_name}=", self)
      end

      if o.respond_to?("#{attr_name}_id=") && respond_to?(:id)
        o.send("#{attr_name}_id=", id)
      end

      o
    end
    instance_variable_set("@#{association_name}", objs)
  end
end

#hash_attr(attr, metadata = {}) ⇒ Object

Defines a hash attribute. This is named hash_attr instead of hash to avoid a conflict with Object#hash



216
217
218
219
220
221
# File 'lib/attribution.rb', line 216

def hash_attr(attr, ={})
  add_attribute(attr, :hash, )
  define_method("#{attr}=") do |arg|
    instance_variable_set("@#{attr}", arg || {})
  end
end

#integer(attr, metadata = {}) ⇒ Object

Defines a integer attribute

Parameters:

  • attr (Symbol)

    The name of the attribute

  • metadata (Hash{Symbol => Object}) (defaults to: {})

    The metadata for the attribute



118
119
120
121
122
123
# File 'lib/attribution.rb', line 118

def integer(attr, ={})
  add_attribute(attr, :integer, )
  define_method("#{attr}=") do |arg|
    instance_variable_set("@#{attr}", arg.nil? ? nil : arg.to_i)
  end
end

#string(attr, metadata = {}) ⇒ Object

Defines a string attribute

Parameters:

  • attr (Symbol)

    The name of the attribute

  • metadata (Hash{Symbol => Object}) (defaults to: {})

    The metadata for the attribute



89
90
91
92
93
94
# File 'lib/attribution.rb', line 89

def string(attr, ={})
  add_attribute(attr, :string, )
  define_method("#{attr}=") do |arg|
    instance_variable_set("@#{attr}", arg.nil? ? nil : arg.to_s)
  end
end

#time(attr, metadata = {}) ⇒ Object

Defines a time attribute

Parameters:

  • attr (Symbol)

    The name of the attribute

  • metadata (Hash{Symbol => Object}) (defaults to: {})

    The metadata for the attribute



172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
# File 'lib/attribution.rb', line 172

def time(attr, ={})
  add_attribute(attr, :time, )
  define_method("#{attr}=") do |arg|
    v = case arg
    when Date, DateTime then arg.to_time
    when Time then arg
    when String then Time.parse(arg)
    when Hash
      args = Util.extract_values(arg, :year, :month, :day, :hour, :min, :sec, :utc_offset)
      args.present? ? Time.new(*args.map(&:to_i)) : nil
    when nil then nil
    else raise ArgumentError.new("can't convert #{arg.class} to Time")
    end
    instance_variable_set("@#{attr}", v)
  end
end

#time_zone(attr, metadata = {}) ⇒ Object

Defines a time zone attribute, based on ActiveSupport::TimeZone

Parameters:

  • attr (Symbol)

    The name of the attribute

  • metadata (Hash{Symbol => Object}) (defaults to: {})

    The metadata for the attribute



193
194
195
196
197
198
# File 'lib/attribution.rb', line 193

def time_zone(attr, ={})
  add_attribute(attr, :time_zone, )
  define_method("#{attr}=") do |arg|
    instance_variable_set("@#{attr}", arg.nil? ? nil : ActiveSupport::TimeZone[arg.to_s])
  end
end