api_resource 0.4.0 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- metadata +179 -123
- data/.document +0 -5
- data/.rspec +0 -5
- data/.travis.yml +0 -4
- data/Gemfile +0 -37
- data/Gemfile.lock +0 -190
- data/Guardfile +0 -27
- data/Rakefile +0 -49
- data/VERSION +0 -1
- data/api_resource.gemspec +0 -180
- data/lib/api_resource.rb +0 -130
- data/lib/api_resource/association_activation.rb +0 -19
- data/lib/api_resource/associations.rb +0 -218
- data/lib/api_resource/associations/association_proxy.rb +0 -116
- data/lib/api_resource/associations/belongs_to_remote_object_proxy.rb +0 -16
- data/lib/api_resource/associations/dynamic_resource_scope.rb +0 -23
- data/lib/api_resource/associations/generic_scope.rb +0 -68
- data/lib/api_resource/associations/has_many_remote_object_proxy.rb +0 -16
- data/lib/api_resource/associations/has_many_through_remote_object_proxy.rb +0 -13
- data/lib/api_resource/associations/has_one_remote_object_proxy.rb +0 -24
- data/lib/api_resource/associations/multi_argument_resource_scope.rb +0 -15
- data/lib/api_resource/associations/multi_object_proxy.rb +0 -84
- data/lib/api_resource/associations/related_object_hash.rb +0 -12
- data/lib/api_resource/associations/relation_scope.rb +0 -25
- data/lib/api_resource/associations/resource_scope.rb +0 -32
- data/lib/api_resource/associations/scope.rb +0 -132
- data/lib/api_resource/associations/single_object_proxy.rb +0 -82
- data/lib/api_resource/attributes.rb +0 -243
- data/lib/api_resource/base.rb +0 -717
- data/lib/api_resource/callbacks.rb +0 -45
- data/lib/api_resource/connection.rb +0 -195
- data/lib/api_resource/core_extensions.rb +0 -7
- data/lib/api_resource/custom_methods.rb +0 -117
- data/lib/api_resource/decorators.rb +0 -6
- data/lib/api_resource/decorators/caching_decorator.rb +0 -20
- data/lib/api_resource/exceptions.rb +0 -99
- data/lib/api_resource/formats.rb +0 -22
- data/lib/api_resource/formats/json_format.rb +0 -25
- data/lib/api_resource/formats/xml_format.rb +0 -36
- data/lib/api_resource/local.rb +0 -12
- data/lib/api_resource/log_subscriber.rb +0 -15
- data/lib/api_resource/mocks.rb +0 -277
- data/lib/api_resource/model_errors.rb +0 -82
- data/lib/api_resource/observing.rb +0 -27
- data/lib/api_resource/railtie.rb +0 -24
- data/lib/api_resource/scopes.rb +0 -48
- data/nohup.out +0 -63
- data/spec/lib/api_resource_spec.rb +0 -43
- data/spec/lib/associations_spec.rb +0 -751
- data/spec/lib/attributes_spec.rb +0 -191
- data/spec/lib/base_spec.rb +0 -655
- data/spec/lib/callbacks_spec.rb +0 -68
- data/spec/lib/connection_spec.rb +0 -137
- data/spec/lib/local_spec.rb +0 -20
- data/spec/lib/mocks_spec.rb +0 -45
- data/spec/lib/model_errors_spec.rb +0 -29
- data/spec/lib/prefixes_spec.rb +0 -107
- data/spec/spec_helper.rb +0 -82
- data/spec/support/mocks/association_mocks.rb +0 -63
- data/spec/support/mocks/error_resource_mocks.rb +0 -21
- data/spec/support/mocks/prefix_model_mocks.rb +0 -5
- data/spec/support/mocks/test_resource_mocks.rb +0 -44
- data/spec/support/requests/association_requests.rb +0 -31
- data/spec/support/requests/error_resource_requests.rb +0 -25
- data/spec/support/requests/prefix_model_requests.rb +0 -7
- data/spec/support/requests/test_resource_requests.rb +0 -38
- data/spec/support/test_resource.rb +0 -72
- data/spec/tmp/DIR +0 -0
data/lib/api_resource.rb
DELETED
@@ -1,130 +0,0 @@
|
|
1
|
-
require 'active_support'
|
2
|
-
require 'active_support/inflector'
|
3
|
-
require 'active_support/core_ext'
|
4
|
-
require 'api_resource/core_extensions'
|
5
|
-
|
6
|
-
require 'active_model'
|
7
|
-
|
8
|
-
require 'log4r'
|
9
|
-
require 'log4r/outputter/consoleoutputters'
|
10
|
-
|
11
|
-
require 'api_resource/exceptions'
|
12
|
-
|
13
|
-
require 'differ'
|
14
|
-
require 'colorize'
|
15
|
-
|
16
|
-
module ApiResource
|
17
|
-
|
18
|
-
extend ActiveSupport::Autoload
|
19
|
-
|
20
|
-
autoload :Associations
|
21
|
-
autoload :AssociationActivation
|
22
|
-
autoload :Attributes
|
23
|
-
autoload :Base
|
24
|
-
autoload :Callbacks
|
25
|
-
autoload :Connection
|
26
|
-
autoload :CustomMethods
|
27
|
-
autoload :Decorators
|
28
|
-
autoload :Formats
|
29
|
-
autoload :Local
|
30
|
-
autoload :LogSubscriber
|
31
|
-
autoload :Mocks
|
32
|
-
autoload :ModelErrors
|
33
|
-
autoload :Observing
|
34
|
-
autoload :Scopes
|
35
|
-
autoload :Validations
|
36
|
-
|
37
|
-
require 'api_resource/railtie'
|
38
|
-
|
39
|
-
mattr_writer :logger
|
40
|
-
mattr_accessor :raise_missing_definition_error; self.raise_missing_definition_error = false
|
41
|
-
|
42
|
-
DEFAULT_TIMEOUT = 10 # seconds
|
43
|
-
|
44
|
-
# Load a fix for inflections for words ending in ess
|
45
|
-
ActiveSupport::Inflector.inflections do |inflect|
|
46
|
-
inflect.singular(/ess$/i, 'ess')
|
47
|
-
end
|
48
|
-
|
49
|
-
def self.load_mocks_and_factories
|
50
|
-
require 'hash_dealer'
|
51
|
-
Mocks.clear_endpoints
|
52
|
-
Mocks.init
|
53
|
-
|
54
|
-
Dir["#{File.dirname(__FILE__)}/../spec/support/requests/*.rb"].each {|f|
|
55
|
-
require f
|
56
|
-
}
|
57
|
-
Dir["#{File.dirname(__FILE__)}/../spec/support/**/*.rb"].each {|f|
|
58
|
-
require f
|
59
|
-
}
|
60
|
-
end
|
61
|
-
|
62
|
-
class << self
|
63
|
-
|
64
|
-
delegate :site, :site=, :format, :format=,
|
65
|
-
:token, :token=, :timeout,
|
66
|
-
:open_timeout,
|
67
|
-
:reset_connection, :ttl, :ttl=,
|
68
|
-
:to => ApiResource::Base
|
69
|
-
|
70
|
-
end
|
71
|
-
|
72
|
-
def self.cache(reset = false)
|
73
|
-
@cache = nil if reset
|
74
|
-
@cache ||= begin
|
75
|
-
defined?(Rails) ? Rails.cache : ActiveSupport::Cache::MemoryStore.new
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
# set the timeout val and reset the connection
|
80
|
-
def self.timeout=(val)
|
81
|
-
ApiResource::Base.timeout = val
|
82
|
-
self.reset_connection
|
83
|
-
val
|
84
|
-
end
|
85
|
-
|
86
|
-
# set the timeout val and reset the connection
|
87
|
-
def self.open_timeout=(val)
|
88
|
-
ApiResource::Base.open_timeout = val
|
89
|
-
self.reset_connection
|
90
|
-
val
|
91
|
-
end
|
92
|
-
self.timeout = self.open_timeout = DEFAULT_TIMEOUT
|
93
|
-
|
94
|
-
# Run a block with a given token - useful for AroundFilters
|
95
|
-
def self.with_token(new_token, &block)
|
96
|
-
old_token = self.token
|
97
|
-
begin
|
98
|
-
self.token = new_token
|
99
|
-
yield
|
100
|
-
ensure
|
101
|
-
self.token = old_token
|
102
|
-
end
|
103
|
-
end
|
104
|
-
|
105
|
-
def self.with_ttl(new_ttl, &block)
|
106
|
-
old_ttl = self.ttl
|
107
|
-
begin
|
108
|
-
self.ttl = new_ttl
|
109
|
-
yield
|
110
|
-
ensure
|
111
|
-
self.ttl = old_ttl
|
112
|
-
end
|
113
|
-
end
|
114
|
-
|
115
|
-
# logger
|
116
|
-
def self.logger
|
117
|
-
return @logger if @logger
|
118
|
-
@logger = Log4r::Logger.new("api_resource")
|
119
|
-
@logger.outputters = [Log4r::StdoutOutputter.new('console')]
|
120
|
-
@logger.level = Log4r::INFO
|
121
|
-
@logger
|
122
|
-
end
|
123
|
-
|
124
|
-
# Use this method to enable logging in the future
|
125
|
-
# def self.logging(val = nil)
|
126
|
-
# return (@@logging || false) unless val
|
127
|
-
# return @@logging = val
|
128
|
-
# end
|
129
|
-
|
130
|
-
end
|
@@ -1,19 +0,0 @@
|
|
1
|
-
module ApiResource
|
2
|
-
module AssociationActivation
|
3
|
-
extend ActiveSupport::Concern
|
4
|
-
|
5
|
-
included do
|
6
|
-
class_attribute :association_types
|
7
|
-
# our default association types
|
8
|
-
self.association_types = {:belongs_to => :single, :has_one => :single, :has_many => :multi}
|
9
|
-
end
|
10
|
-
|
11
|
-
module ClassMethods
|
12
|
-
def activate_associations(assoc_types = nil)
|
13
|
-
self.association_types = assoc_types unless assoc_types.nil?
|
14
|
-
self.send(:include, ApiResource::Associations)
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
end
|
19
|
-
end
|
@@ -1,218 +0,0 @@
|
|
1
|
-
require 'active_support'
|
2
|
-
require 'active_support/string_inquirer'
|
3
|
-
require 'api_resource/association_activation'
|
4
|
-
require 'api_resource/associations/relation_scope'
|
5
|
-
require 'api_resource/associations/resource_scope'
|
6
|
-
require 'api_resource/associations/dynamic_resource_scope'
|
7
|
-
require 'api_resource/associations/generic_scope'
|
8
|
-
require 'api_resource/associations/multi_argument_resource_scope'
|
9
|
-
require 'api_resource/associations/multi_object_proxy'
|
10
|
-
require 'api_resource/associations/single_object_proxy'
|
11
|
-
require 'api_resource/associations/belongs_to_remote_object_proxy'
|
12
|
-
require 'api_resource/associations/has_one_remote_object_proxy'
|
13
|
-
require 'api_resource/associations/has_many_remote_object_proxy'
|
14
|
-
require 'api_resource/associations/has_many_through_remote_object_proxy'
|
15
|
-
require 'api_resource/associations/related_object_hash'
|
16
|
-
|
17
|
-
module ApiResource
|
18
|
-
|
19
|
-
module Associations
|
20
|
-
extend ActiveSupport::Concern
|
21
|
-
|
22
|
-
included do
|
23
|
-
|
24
|
-
unless self.ancestors.include?(ApiResource::AssociationActivation)
|
25
|
-
raise Exception.new(
|
26
|
-
"Can't include Associations without AssociationActivation"
|
27
|
-
)
|
28
|
-
end
|
29
|
-
|
30
|
-
class_attribute :related_objects
|
31
|
-
attr_accessor :assoc_attributes
|
32
|
-
|
33
|
-
define_method(:assoc_attributes) do
|
34
|
-
@assoc_attributes ||= Hash.new
|
35
|
-
end
|
36
|
-
|
37
|
-
self.clear_related_objects
|
38
|
-
|
39
|
-
# we need to add an inherited method here, but it can't happen
|
40
|
-
# until after this module in included/extended, so it's in its own
|
41
|
-
# little mini module
|
42
|
-
extend InheritedMethod
|
43
|
-
|
44
|
-
self.define_association_methods
|
45
|
-
|
46
|
-
end
|
47
|
-
|
48
|
-
# module methods to include the proper associations in various libraries - this is usually loaded in Railties
|
49
|
-
def self.activate_active_record
|
50
|
-
ActiveRecord::Base.class_eval do
|
51
|
-
include ApiResource::AssociationActivation
|
52
|
-
self.activate_associations(
|
53
|
-
:has_many_remote => :has_many_remote,
|
54
|
-
:belongs_to_remote => :belongs_to_remote,
|
55
|
-
:has_one_remote => :has_one_remote,
|
56
|
-
)
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
|
-
module InheritedMethod
|
61
|
-
# define a method to reset our related objects
|
62
|
-
def inherited(descendant)
|
63
|
-
# we only want to do this in direct descendants of ApiResoruce::Base
|
64
|
-
if self == ApiResource::Base
|
65
|
-
descendant.clear_related_objects
|
66
|
-
else
|
67
|
-
descendant.clone_related_objects
|
68
|
-
end
|
69
|
-
super(descendant)
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
73
|
-
module ClassMethods
|
74
|
-
|
75
|
-
# Define the methods for creating and testing for associations, unfortunately
|
76
|
-
# scopes are different enough to require different methods :(
|
77
|
-
def define_association_methods
|
78
|
-
self.association_types.each_key do |assoc|
|
79
|
-
self.instance_eval <<-EOE, __FILE__, __LINE__ + 1
|
80
|
-
def #{assoc}(*args)
|
81
|
-
options = args.extract_options!
|
82
|
-
options = options.with_indifferent_access
|
83
|
-
# Raise an error if we have multiple args and options
|
84
|
-
raise "Invalid arguments to #{assoc}" unless options.blank? || args.length == 1
|
85
|
-
args.each do |arg|
|
86
|
-
klass_name = (options[:class_name] ? options[:class_name].to_s.classify : arg.to_s.classify)
|
87
|
-
# add this to any descendants - the other methods etc are handled by inheritance
|
88
|
-
([self] + self.descendants).each do |klass|
|
89
|
-
#We need to merge upon itself to generate a new object since the children all share their related objects with each other
|
90
|
-
klass.related_objects = klass.related_objects.merge(:#{assoc} => klass.related_objects[:#{assoc}].merge(arg.to_sym => klass_name))
|
91
|
-
end
|
92
|
-
# We need to define reader and writer methods here
|
93
|
-
define_association_as_attribute(:#{assoc}, arg)
|
94
|
-
end
|
95
|
-
end
|
96
|
-
|
97
|
-
def #{assoc}?(name)
|
98
|
-
return self.related_objects[:#{assoc}][name.to_s.pluralize.to_sym].present? || self.related_objects[:#{assoc}][name.to_s.singularize.to_sym].present?
|
99
|
-
end
|
100
|
-
|
101
|
-
def #{assoc}_class_name(name)
|
102
|
-
raise "No such" + :#{assoc}.to_s + " association on #{name}" unless self.#{assoc}?(name)
|
103
|
-
return self.find_namespaced_class_name(self.related_objects[:#{assoc}][name.to_sym])
|
104
|
-
end
|
105
|
-
|
106
|
-
EOE
|
107
|
-
# For convenience we will define the methods for testing for the existence of an association
|
108
|
-
# and getting the class for an association as instance methods too to avoid tons of self.class calls
|
109
|
-
self.class_eval <<-EOE, __FILE__, __LINE__ + 1
|
110
|
-
def #{assoc}?(name)
|
111
|
-
return self.class.#{assoc}?(name)
|
112
|
-
end
|
113
|
-
|
114
|
-
def #{assoc}_class_name(name)
|
115
|
-
return self.class.#{assoc}_class_name(name)
|
116
|
-
end
|
117
|
-
EOE
|
118
|
-
end
|
119
|
-
end
|
120
|
-
|
121
|
-
def association?(assoc)
|
122
|
-
self.related_objects.any? do |key, value|
|
123
|
-
next if key.to_s == "scopes"
|
124
|
-
value.detect { |k,v| k.to_sym == assoc.to_sym }
|
125
|
-
end
|
126
|
-
end
|
127
|
-
|
128
|
-
def association_names
|
129
|
-
# structure is {:has_many => {"myname" => "ClassName"}}
|
130
|
-
self.related_objects.clone.delete_if{|k,v| k.to_s == "scopes"}.collect{|k,v| v.keys.collect(&:to_sym)}.flatten
|
131
|
-
end
|
132
|
-
|
133
|
-
def association_class_name(assoc)
|
134
|
-
raise ArgumentError, "#{assoc} is not a valid association of #{self}" unless self.association?(assoc)
|
135
|
-
result = self.related_objects.detect do |key,value|
|
136
|
-
ret = value.detect{|k,v| k.to_sym == assoc.to_sym }
|
137
|
-
return self.find_namespaced_class_name(ret[1]) if ret
|
138
|
-
end
|
139
|
-
end
|
140
|
-
|
141
|
-
protected
|
142
|
-
|
143
|
-
def clear_related_objects
|
144
|
-
# Hash to hold onto the definitions of the related objects
|
145
|
-
self.related_objects = RelatedObjectHash.new
|
146
|
-
self.association_types.keys.each do |type|
|
147
|
-
self.related_objects[type] = RelatedObjectHash.new({})
|
148
|
-
end
|
149
|
-
|
150
|
-
# TODO :Remove scopes from related_objects.
|
151
|
-
self.related_objects[:scopes] = RelatedObjectHash.new({})
|
152
|
-
end
|
153
|
-
|
154
|
-
def clone_related_objects
|
155
|
-
# Hash to hold onto the definitions of the related objects
|
156
|
-
self.related_objects = self.related_objects.clone
|
157
|
-
self.association_types.keys.each do |type|
|
158
|
-
self.related_objects[type] = self.related_objects[type].clone
|
159
|
-
end
|
160
|
-
# TODO :Remove scopes from related_objects.
|
161
|
-
self.related_objects[:scopes] = self.related_objects[:scopes].clone
|
162
|
-
end
|
163
|
-
|
164
|
-
def define_association_as_attribute(assoc_type, assoc_name)
|
165
|
-
# set up dirty tracking for associations
|
166
|
-
|
167
|
-
self.class_eval <<-EOE, __FILE__, __LINE__ + 1
|
168
|
-
def #{assoc_name}
|
169
|
-
self.assoc_attributes[:#{assoc_name}] ||= (self.attributes[:#{assoc_name}] || #{self.association_types[assoc_type.to_sym].to_s.classify}ObjectProxy.new(self.association_class_name('#{assoc_name}'), nil, self))
|
170
|
-
end
|
171
|
-
def #{assoc_name}=(val)
|
172
|
-
# get old internal object
|
173
|
-
old_internal_object = self.#{assoc_name}.internal_object
|
174
|
-
self.#{assoc_name}.internal_object = val
|
175
|
-
#{assoc_name}_will_change! unless self.#{assoc_name} == old_internal_object
|
176
|
-
self.#{assoc_name}.internal_object
|
177
|
-
end
|
178
|
-
def #{assoc_name}?
|
179
|
-
self.#{assoc_name}.internal_object.present?
|
180
|
-
end
|
181
|
-
EOE
|
182
|
-
end
|
183
|
-
|
184
|
-
def find_namespaced_class_name(klass)
|
185
|
-
# return the name if it is itself namespaced
|
186
|
-
return klass if klass =~ /::/
|
187
|
-
ancestors = self.name.split("::")
|
188
|
-
if ancestors.size > 1
|
189
|
-
receiver = Object
|
190
|
-
namespaces = ancestors[0..-2].collect do |mod|
|
191
|
-
receiver = receiver.const_get(mod)
|
192
|
-
end
|
193
|
-
if namespace = namespaces.reverse.detect{|ns| ns.const_defined?(klass, false)}
|
194
|
-
return namespace.const_get(klass).name
|
195
|
-
end
|
196
|
-
end
|
197
|
-
|
198
|
-
return klass
|
199
|
-
end
|
200
|
-
|
201
|
-
end
|
202
|
-
|
203
|
-
def association?(assoc)
|
204
|
-
self.class.association?(assoc)
|
205
|
-
end
|
206
|
-
|
207
|
-
def association_class_name(assoc)
|
208
|
-
self.class.association_class_name(assoc)
|
209
|
-
end
|
210
|
-
|
211
|
-
# list of all association names
|
212
|
-
def association_names
|
213
|
-
self.class.association_names
|
214
|
-
end
|
215
|
-
|
216
|
-
end
|
217
|
-
|
218
|
-
end
|
@@ -1,116 +0,0 @@
|
|
1
|
-
module ApiResource
|
2
|
-
|
3
|
-
module Associations
|
4
|
-
|
5
|
-
class AssociationProxy
|
6
|
-
|
7
|
-
|
8
|
-
cattr_accessor :remote_path_element; self.remote_path_element = :service_uri
|
9
|
-
cattr_accessor :include_class_scopes; self.include_class_scopes = true
|
10
|
-
|
11
|
-
attr_accessor :owner, :loaded, :klass, :internal_object, :remote_path, :scopes, :times_loaded
|
12
|
-
|
13
|
-
# TODO: added owner - moved it to the end because the tests don't use it - it's useful here though
|
14
|
-
def initialize(klass_name, contents, owner = nil)
|
15
|
-
raise "Cannot create an association proxy to the unknown object #{klass_name}" unless defined?(klass_name.to_s.classify)
|
16
|
-
# A simple attr_accessor for testing purposes
|
17
|
-
self.times_loaded = 0
|
18
|
-
self.owner = owner
|
19
|
-
self.klass = klass_name.to_s.classify.constantize
|
20
|
-
self.load(contents)
|
21
|
-
self.loaded = {}.with_indifferent_access
|
22
|
-
if self.class.include_class_scopes
|
23
|
-
self.scopes = self.scopes.reverse_merge(self.klass.scopes)
|
24
|
-
end
|
25
|
-
# Now that we have set up all the scopes with the load method we need to create methods
|
26
|
-
self.scopes.each do |key, _|
|
27
|
-
next if self.respond_to?(key)
|
28
|
-
self.instance_eval <<-EOE, __FILE__, __LINE__ + 1
|
29
|
-
def #{key}(opts = {})
|
30
|
-
@#{key} ||= ApiResource::Associations::RelationScope.new(self, :#{key}, opts)
|
31
|
-
end
|
32
|
-
EOE
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
def serializable_hash(options = {})
|
37
|
-
raise "Not Implemented: This method must be implemented in a subclass"
|
38
|
-
end
|
39
|
-
|
40
|
-
def scopes
|
41
|
-
@scopes ||= {}.with_indifferent_access
|
42
|
-
end
|
43
|
-
|
44
|
-
def scope?(scp)
|
45
|
-
self.scopes.keys.include?(scp.to_s)
|
46
|
-
end
|
47
|
-
|
48
|
-
def internal_object
|
49
|
-
@internal_object ||= self.load_scope_with_options(:all, {})
|
50
|
-
end
|
51
|
-
|
52
|
-
def blank?
|
53
|
-
self.internal_object.blank?
|
54
|
-
end
|
55
|
-
alias_method :empty?, :blank?
|
56
|
-
|
57
|
-
def method_missing(method, *args, &block)
|
58
|
-
self.internal_object.send(method, *args, &block)
|
59
|
-
end
|
60
|
-
|
61
|
-
def reload
|
62
|
-
if self
|
63
|
-
remove_instance_variable(:@internal_object) if instance_variable_defined?(:@internal_object)
|
64
|
-
self.load(self.load_from_remote({}))
|
65
|
-
self
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
def to_s
|
70
|
-
self.internal_object.to_s
|
71
|
-
end
|
72
|
-
|
73
|
-
def inspect
|
74
|
-
self.internal_object.inspect
|
75
|
-
end
|
76
|
-
|
77
|
-
def ==(other)
|
78
|
-
raise "Not Implemented: This method must be implemented in a subclass"
|
79
|
-
end
|
80
|
-
|
81
|
-
protected
|
82
|
-
# This method loads a particular scope with a set of options from the remote server
|
83
|
-
def load_scope_with_options(scope, options)
|
84
|
-
raise "Not Implemented: This method must be implemented in a subclass"
|
85
|
-
end
|
86
|
-
# This method is a helper to initialize for loading the data passed in to create this object
|
87
|
-
def load(contents)
|
88
|
-
raise "Not Implemented: This method must be implemented in a subclass"
|
89
|
-
end
|
90
|
-
|
91
|
-
# get the remote URI based on our config and options
|
92
|
-
def build_load_path(options)
|
93
|
-
path = self.remote_path
|
94
|
-
# add a format if it doesn't exist and there is no query string yet
|
95
|
-
path += ".#{self.klass.format.extension}" unless path =~ /\./ || path =~/\?/
|
96
|
-
# add the query string, allowing for other user-provided options in the remote_path if we have options
|
97
|
-
unless options.blank?
|
98
|
-
path += (path =~ /\?/ ? "&" : "?") + options.to_query
|
99
|
-
end
|
100
|
-
path
|
101
|
-
end
|
102
|
-
|
103
|
-
# get data from the remote server
|
104
|
-
def load_from_remote(options)
|
105
|
-
self.klass.connection.get(self.build_load_path(options))
|
106
|
-
end
|
107
|
-
# This method create the key for the loaded hash, it ensures that a unique set of scopes
|
108
|
-
# with a unique set of options is only loaded once
|
109
|
-
def loaded_hash_key(scope, options)
|
110
|
-
options.to_a.sort.inject(scope) {|accum,(k,v)| accum << "_#{k}_#{v}"}
|
111
|
-
end
|
112
|
-
end
|
113
|
-
|
114
|
-
end
|
115
|
-
|
116
|
-
end
|