Class: ApiResource::Base

Inherits:
Object
  • Object
show all
Extended by:
ActiveModel::Naming
Includes:
Associations, Attributes, Callbacks, ModelErrors
Defined in:
lib/api_resource/base.rb,
lib/api_resource/base.rb

Constant Summary

Constants included from Associations

Associations::ASSOCIATION_TYPES

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(attributes = {}) ⇒ Base

Returns a new instance of Base.



311
312
313
314
# File 'lib/api_resource/base.rb', line 311

def initialize(attributes = {})
  @prefix_options = {}
  load(attributes)
end

Instance Attribute Details

#prefix_optionsObject

Returns the value of attribute prefix_options.



17
18
19
# File 'lib/api_resource/base.rb', line 17

def prefix_options
  @prefix_options
end

Class Method Details

.all(*args) ⇒ Object

This is an alias for find(:all). You can pass in all the same arguments to this method as you can to find(:all)



199
200
201
# File 'lib/api_resource/base.rb', line 199

def all(*args)
  find(:all, *args)
end

.build(attributes = {}) ⇒ Object



161
162
163
# File 'lib/api_resource/base.rb', line 161

def build(attributes = {})
  self.new(attributes)
end

.collection_path(prefix_options = {}, query_options = nil) ⇒ Object



156
157
158
159
# File 'lib/api_resource/base.rb', line 156

def collection_path(prefix_options = {}, query_options = nil)
  prefix_options, query_options = split_options(prefix_options) if query_options.nil?
  "#{prefix(prefix_options)}#{collection_name}.#{format.extension}#{query_string(query_options)}"
end

.connection(refresh = false) ⇒ Object



107
108
109
110
111
# File 'lib/api_resource/base.rb', line 107

def connection(refresh = false)
  @connection = Connection.new(self.site, self.format) if refresh || @connection.nil?
  @connection.timeout = self.timeout
  @connection
end

.create(attributes = {}) ⇒ Object



165
166
167
# File 'lib/api_resource/base.rb', line 165

def create(attributes = {})
  self.new(attributes).tap{ |resource| resource.save }
end

.delete(id, options = {}) ⇒ Object

Deletes the resources with the ID in the id parameter.

Options

All options specify prefix and query parameters.

Examples

Event.delete(2) # sends DELETE /events/2

Event.create(:name => 'Free Concert', :location => 'Community Center')
my_event = Event.find(:first) # let's assume this is event with ID 7
Event.delete(my_event.id) # sends DELETE /events/7

# Let's assume a request to events/5/cancel.xml
Event.delete(params[:id]) # sends DELETE /events/5


218
219
220
# File 'lib/api_resource/base.rb', line 218

def delete(id, options = {})
  connection.delete(element_path(id, options))
end

.element_path(id, prefix_options = {}, query_options = nil) ⇒ Object

alias_method :set_prefix, :prefix= alias_method :set_element_name, :element_name= alias_method :set_collection_name, :collection_name=



147
148
149
150
# File 'lib/api_resource/base.rb', line 147

def element_path(id, prefix_options = {}, query_options = nil)
  prefix_options, query_options = split_options(prefix_options) if query_options.nil?
  "#{prefix(prefix_options)}#{collection_name}/#{URI.escape id.to_s}.#{format.extension}#{query_string(query_options)}"
end

.find(*arguments) ⇒ Object



169
170
171
172
173
174
175
176
177
178
179
180
# File 'lib/api_resource/base.rb', line 169

def find(*arguments)
  scope   = arguments.slice!(0)
  options = arguments.slice!(0) || {}

  case scope
    when :all   then find_every(options)
    when :first then find_every(options).first
    when :last  then find_every(options).last
    when :one   then find_one(options)
    else             find_single(scope, options)
  end
end

.first(*args) ⇒ Object

A convenience wrapper for find(:first, *args). You can pass in all the same arguments to this method as you can to find(:first).



186
187
188
# File 'lib/api_resource/base.rb', line 186

def first(*args)
  find(:first, *args)
end

.formatObject

Default format is json



98
99
100
# File 'lib/api_resource/base.rb', line 98

def format
  read_inheritable_attribute(:format) || ApiResource::Formats::JsonFormat
end

.format=(mime_type_or_format) ⇒ Object



91
92
93
94
95
# File 'lib/api_resource/base.rb', line 91

def format=(mime_type_or_format)
  format = mime_type_or_format.is_a?(Symbol) ? ApiResource::Formats[mime_type_or_format] : mime_type_or_format
  write_inheritable_attribute(:format, format)
  self.connection.format = format if self.site
end

.headersObject



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

def headers
  @headers || {}
end

.inherited(klass) ⇒ Object



25
26
27
28
29
30
31
32
33
34
35
36
37
38
# File 'lib/api_resource/base.rb', line 25

def inherited(klass)
  # Call the methods of the superclass to make sure inheritable accessors and the like have been inherited
  super
  # Now we need to define the inherited method on the klass that's doing the inheriting
  # it calls super which will allow the chaining effect we need
  klass.instance_eval <<-EOE, __FILE__, __LINE__ + 1
    def inherited(klass)
      super
    end
  EOE
  # Now we can make a call to setup the inheriting klass with its attributes
  klass.set_class_attributes_upon_load unless klass.instance_variable_defined?(:@class_data)
  klass.instance_variable_set(:@class_data, true)
end

.last(*args) ⇒ Object

A convenience wrapper for find(:last, *args). You can pass in all the same arguments to this method as you can to find(:last).



193
194
195
# File 'lib/api_resource/base.rb', line 193

def last(*args)
  find(:last, *args)
end

.new_element_path(prefix_options = {}) ⇒ Object



152
153
154
# File 'lib/api_resource/base.rb', line 152

def new_element_path(prefix_options = {})
  "#{prefix(prefix_options)}#{collection_name}/new.#{format.extension}"
end

.prefix(options = {}) ⇒ Object



117
118
119
120
121
122
# File 'lib/api_resource/base.rb', line 117

def prefix(options = {})
  default = (self.site ? self.site.path : '/')
  default << '/' unless default[-1..-1] == '/'
  self.prefix = default
  prefix(options)
end

.prefix=(value = '/') ⇒ Object



129
130
131
132
133
134
135
136
137
138
139
140
141
# File 'lib/api_resource/base.rb', line 129

def prefix=(value = '/')
  prefix_call = value.gsub(/:\w+/) { |key| "\#{URI.escape options[#{key}].to_s}"}
  @prefix_parameters = nil
  silence_warnings do
    instance_eval <<-EOE, __FILE__, __LINE__ + 1
      def prefix_source() "#{value}" end
      def prefix(options={}) "#{prefix_call}" end
    EOE
  end
rescue Exception => e
  logger.error "Couldn't set prefix: #{e}\n #{code}" if logger
  raise
end

.prefix_sourceObject



124
125
126
127
# File 'lib/api_resource/base.rb', line 124

def prefix_source
  prefix
  prefix_source
end

.reload_class_attributesObject



70
71
72
73
74
75
# File 'lib/api_resource/base.rb', line 70

def reload_class_attributes
  # clear the public_attribute_names, protected_attribute_names
  self.clear_attributes
  self.clear_associations
  self.set_class_attributes_upon_load
end

.set_class_attributes_upon_loadObject

This makes a request to new_element_path



42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
# File 'lib/api_resource/base.rb', line 42

def set_class_attributes_upon_load
  begin
    class_data = self.connection.get(self.new_element_path)
    # Attributes go first
    if class_data["attributes"]
      define_attributes *(class_data["attributes"]["public"] || [])
      define_protected_attributes *(class_data["attributes"]["protected"] || [])
    end
    # Then scopes
    if class_data["scopes"]
      class_data["scopes"].each do |hash|
        self.scope hash.first[0], hash.first[1]
      end
    end
    # Then associations
    if class_data["associations"]
      class_data["associations"].each do |(key,hash)|
        hash.each do |assoc_name, assoc_options|
          self.send(key, assoc_name, assoc_options)
        end
      end
    end
  # Swallow up any loading errors because the site may be incorrect
  rescue Exception => e
    return nil
  end
end

.site=(site) ⇒ Object



77
78
79
80
81
82
83
84
85
86
87
88
# File 'lib/api_resource/base.rb', line 77

def site=(site)
  @connection = nil
  # reset class attributes and try to reload them if the site changed
  unless site.to_s == self.site.to_s
    self.reload_class_attributes
  end
  if site.nil?
    write_inheritable_attribute(:site, nil)
  else
    write_inheritable_attribute(:site, create_site_uri_from(site))
  end
end

.timeout=(timeout) ⇒ Object



102
103
104
105
# File 'lib/api_resource/base.rb', line 102

def timeout=(timeout)
  @connection = nil
  write_inheritable_attribute(:timeout, timeout)
end

Instance Method Details

#==(other) ⇒ Object



334
335
336
# File 'lib/api_resource/base.rb', line 334

def ==(other)
  other.equal?(self) || (other.instance_of?(self.class) && other.id == self.id && other.prefix_options == self.prefix_options)
end

#destroyObject



361
362
363
# File 'lib/api_resource/base.rb', line 361

def destroy
  connection.delete(element_path(self.id), self.class.headers)
end

#dupObject



346
347
348
349
350
351
# File 'lib/api_resource/base.rb', line 346

def dup
  self.class.new.tap do |resource|
    resource.attributes = self.attributes
    resource.prefix_options = @prefix_options
  end
end

#encode(options = {}) ⇒ Object



365
366
367
# File 'lib/api_resource/base.rb', line 365

def encode(options = {})
  self.send("to_#{self.class.format.extension}", options)
end

#eql?(other) ⇒ Boolean

Returns:

  • (Boolean)


338
339
340
# File 'lib/api_resource/base.rb', line 338

def eql?(other)
  self == other
end

#hashObject



342
343
344
# File 'lib/api_resource/base.rb', line 342

def hash
  id.hash
end

#idObject



325
326
327
# File 'lib/api_resource/base.rb', line 325

def id
  self.attributes[self.class.primary_key]
end

#id=(id) ⇒ Object

Bypass dirty tracking for this field



330
331
332
# File 'lib/api_resource/base.rb', line 330

def id=(id)
  attributes[self.class.primary_key] = id
end

#load(attributes) ⇒ Object

Raises:

  • (ArgumentError)


373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
# File 'lib/api_resource/base.rb', line 373

def load(attributes)
  return if attributes.nil?
  raise ArgumentError, "expected an attributes Hash, got #{attributes.inspect}" unless attributes.is_a?(Hash)
  @prefix_options, attributes = split_options(attributes)
 
  attributes.symbolize_keys.each do |key, value|
    # If this attribute doesn't exist define it as a protected attribute
    self.class.define_protected_attributes(key) unless self.respond_to?(key)
    self.attributes[key] =
    case value
      when Array
        if self.has_many?(key)
          MultiObjectProxy.new(self.has_many_class_name(key), value)
        elsif self.association?(key)
          raise ArgumentError, "Expected a hash value or nil, got: #{value.inspect}"
        else
          value
        end
      when Hash
        if self.has_many?(key)
          MultiObjectProxy.new(self.has_many_class_name(key), value)
        elsif self.association?(key)
          SingleObjectProxy.new(self.association_class_name(key), value)
        else
          value
        end
      when NilClass
        # If it's nil and an association then create a blank object
        if self.has_many?(key)
          return MultiObjectProxy.new(self.has_many_class_name(key), [])
        elsif self.association?(key)
          SingleObjectProxy.new(self.association_class_name(key), value)
        end
      else
        raise ArgumentError, "expected an array or a hash for the association #{key}, got: #{value.inspect}" if self.association?(key)
        value.dup rescue value
    end
  end
  return self
end

#new?Boolean Also known as: new_record?

Returns:

  • (Boolean)


316
317
318
# File 'lib/api_resource/base.rb', line 316

def new?
  id.nil?
end

#persisted?Boolean

Returns:

  • (Boolean)


321
322
323
# File 'lib/api_resource/base.rb', line 321

def persisted?
  !new?
end

#reloadObject



369
370
371
# File 'lib/api_resource/base.rb', line 369

def reload
  self.load(self.class.find(to_param, :params => @prefix_options).attributes)
end

#save(*args) ⇒ Object



353
354
355
# File 'lib/api_resource/base.rb', line 353

def save(*args)
  new? ? create(*args) : update(*args)
end

#save!(*args) ⇒ Object



357
358
359
# File 'lib/api_resource/base.rb', line 357

def save!(*args)
  save(*args) || raise(ApiResource::ResourceInvalid.new(self))
end

#serializable_hash(options = {}) ⇒ Object



433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
# File 'lib/api_resource/base.rb', line 433

def serializable_hash(options = {})
  options[:include_associations] = options[:include_associations] ? options[:include_associations].symbolize_array : []
  options[:include_extras] = options[:include_extras] ? options[:include_extras].symbolize_array : []
  options[:except] ||= []
  ret = self.attributes.inject({}) do |accum, (key,val)|
    # If this is an association and it's in include_associations then include it
    if self.association?(key) && options[:include_associations].include?(key.to_sym)
      accum.merge(key => val.serializable_hash({}))
    elsif options[:include_extras].include?(key.to_sym)
      accum.merge(key => val)
    elsif options[:except].include?(key.to_sym)
      accum
    else
      self.association?(key) || !self.attribute?(key) || self.protected_attribute?(key) ? accum : accum.merge(key => val)
    end
  end
end

#to_json(options = {}) ⇒ Object



429
430
431
# File 'lib/api_resource/base.rb', line 429

def to_json(options = {})
  self.class.include_root_in_json ? {self.class.element_name => self.serializable_hash(options)}.to_json : self.serializable_hash(options).to_json
end

#to_sObject Also known as: inspect

Override to_s and inspect so they only show attributes and not associations, this prevents force loading of associations when we call to_s or inspect on a descendent of base but allows it if we try to evaluate an association directly



418
419
420
# File 'lib/api_resource/base.rb', line 418

def to_s
  return "#<#{self.class}:0x%08x @attributes=#{self.attributes.inject({}){|accum,(k,v)| self.association?(k) ? accum : accum.merge(k => v)}}" % (self.object_id * 2)
end

#to_xml(options = {}) ⇒ Object

Methods for serialization as json or xml, relying on the serializable_hash method



425
426
427
# File 'lib/api_resource/base.rb', line 425

def to_xml(options = {})
  self.serializable_hash(options).to_xml(:root => self.class.element_name)
end