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.
Files changed (68) hide show
  1. metadata +179 -123
  2. data/.document +0 -5
  3. data/.rspec +0 -5
  4. data/.travis.yml +0 -4
  5. data/Gemfile +0 -37
  6. data/Gemfile.lock +0 -190
  7. data/Guardfile +0 -27
  8. data/Rakefile +0 -49
  9. data/VERSION +0 -1
  10. data/api_resource.gemspec +0 -180
  11. data/lib/api_resource.rb +0 -130
  12. data/lib/api_resource/association_activation.rb +0 -19
  13. data/lib/api_resource/associations.rb +0 -218
  14. data/lib/api_resource/associations/association_proxy.rb +0 -116
  15. data/lib/api_resource/associations/belongs_to_remote_object_proxy.rb +0 -16
  16. data/lib/api_resource/associations/dynamic_resource_scope.rb +0 -23
  17. data/lib/api_resource/associations/generic_scope.rb +0 -68
  18. data/lib/api_resource/associations/has_many_remote_object_proxy.rb +0 -16
  19. data/lib/api_resource/associations/has_many_through_remote_object_proxy.rb +0 -13
  20. data/lib/api_resource/associations/has_one_remote_object_proxy.rb +0 -24
  21. data/lib/api_resource/associations/multi_argument_resource_scope.rb +0 -15
  22. data/lib/api_resource/associations/multi_object_proxy.rb +0 -84
  23. data/lib/api_resource/associations/related_object_hash.rb +0 -12
  24. data/lib/api_resource/associations/relation_scope.rb +0 -25
  25. data/lib/api_resource/associations/resource_scope.rb +0 -32
  26. data/lib/api_resource/associations/scope.rb +0 -132
  27. data/lib/api_resource/associations/single_object_proxy.rb +0 -82
  28. data/lib/api_resource/attributes.rb +0 -243
  29. data/lib/api_resource/base.rb +0 -717
  30. data/lib/api_resource/callbacks.rb +0 -45
  31. data/lib/api_resource/connection.rb +0 -195
  32. data/lib/api_resource/core_extensions.rb +0 -7
  33. data/lib/api_resource/custom_methods.rb +0 -117
  34. data/lib/api_resource/decorators.rb +0 -6
  35. data/lib/api_resource/decorators/caching_decorator.rb +0 -20
  36. data/lib/api_resource/exceptions.rb +0 -99
  37. data/lib/api_resource/formats.rb +0 -22
  38. data/lib/api_resource/formats/json_format.rb +0 -25
  39. data/lib/api_resource/formats/xml_format.rb +0 -36
  40. data/lib/api_resource/local.rb +0 -12
  41. data/lib/api_resource/log_subscriber.rb +0 -15
  42. data/lib/api_resource/mocks.rb +0 -277
  43. data/lib/api_resource/model_errors.rb +0 -82
  44. data/lib/api_resource/observing.rb +0 -27
  45. data/lib/api_resource/railtie.rb +0 -24
  46. data/lib/api_resource/scopes.rb +0 -48
  47. data/nohup.out +0 -63
  48. data/spec/lib/api_resource_spec.rb +0 -43
  49. data/spec/lib/associations_spec.rb +0 -751
  50. data/spec/lib/attributes_spec.rb +0 -191
  51. data/spec/lib/base_spec.rb +0 -655
  52. data/spec/lib/callbacks_spec.rb +0 -68
  53. data/spec/lib/connection_spec.rb +0 -137
  54. data/spec/lib/local_spec.rb +0 -20
  55. data/spec/lib/mocks_spec.rb +0 -45
  56. data/spec/lib/model_errors_spec.rb +0 -29
  57. data/spec/lib/prefixes_spec.rb +0 -107
  58. data/spec/spec_helper.rb +0 -82
  59. data/spec/support/mocks/association_mocks.rb +0 -63
  60. data/spec/support/mocks/error_resource_mocks.rb +0 -21
  61. data/spec/support/mocks/prefix_model_mocks.rb +0 -5
  62. data/spec/support/mocks/test_resource_mocks.rb +0 -44
  63. data/spec/support/requests/association_requests.rb +0 -31
  64. data/spec/support/requests/error_resource_requests.rb +0 -25
  65. data/spec/support/requests/prefix_model_requests.rb +0 -7
  66. data/spec/support/requests/test_resource_requests.rb +0 -38
  67. data/spec/support/test_resource.rb +0 -72
  68. data/spec/tmp/DIR +0 -0
@@ -1,16 +0,0 @@
1
- require 'api_resource/associations/single_object_proxy'
2
- module ApiResource
3
- module Associations
4
- class BelongsToRemoteObjectProxy < SingleObjectProxy
5
- def initialize(klass_name, contents, owner)
6
- super
7
- return if self.internal_object
8
- # now if we have an owner and a foreign key, we set the data up to load
9
- if owner && key = owner.send(self.klass.to_s.foreign_key)
10
- self.load({"service_uri" => self.klass.element_path(key), "scopes_only" => true}.merge(self.klass.scopes))
11
- end
12
- true
13
- end
14
- end
15
- end
16
- end
@@ -1,23 +0,0 @@
1
- require 'api_resource/associations/resource_scope'
2
-
3
- module ApiResource
4
- module Associations
5
- class DynamicResourceScope < ResourceScope
6
-
7
- attr_accessor :dynamic_value
8
- # initializer - set up the dynamic value
9
- def initialize(klass, current_scope, dynamic_value, opts = {})
10
- self.dynamic_value = dynamic_value
11
- super(klass, current_scope, opts)
12
- end
13
- # get the to_query value for this resource scope
14
- def to_hash
15
- hsh = self.scopes[self.current_scope].clone
16
- hsh.each_pair do |k,v|
17
- hsh[k] = self.dynamic_value
18
- end
19
- self.parent_hash.merge(hsh)
20
- end
21
- end
22
- end
23
- end
@@ -1,68 +0,0 @@
1
- require 'api_resource/associations/resource_scope'
2
-
3
- module ApiResource
4
- module Associations
5
-
6
- class GenericScope < ResourceScope
7
- attr_reader :name
8
- attr_reader :params
9
- attr_reader :types
10
- attr_reader :values
11
-
12
- # Gets called when a scope is called. Stores everything in
13
- # this class. Sorry, couldn't be bothered to figure out the
14
- # class hierarchy.
15
- #
16
- # klass - ApiResourceBase class
17
- # current_scope - sym for the scope
18
- # *args - arguments being passed to the scope
19
- def initialize(klass, current_scope, *args)
20
-
21
- @name = current_scope # contains sym with scope ie :for_provider
22
- @params = klass.related_objects[:scopes][current_scope].keys
23
- @types = klass.related_objects[:scopes][current_scope].values
24
-
25
- # Bail if we have crap
26
- if @params == nil
27
- raise "Scope #{@name} does not exist #{klass.name}. Scopes: #{klass.related_objects[:scopes]}"
28
- end
29
-
30
- # extract parent scope stuff
31
- opts = {}
32
- last_arg = args[args.count - 1]
33
- if last_arg != nil && last_arg.is_a?(Hash) && last_arg[:parent] != nil
34
- args = args.slice(0, args.count - 1)
35
- opts = last_arg
36
- end
37
-
38
- # walk through parameters and types and assign values from *args to parameters
39
- @values = []
40
- @params.count.times do |i|
41
- if @types[i] == :rest
42
- @values << args.slice(i, args.count)
43
- else
44
- @values << args[i]
45
- end
46
- end
47
-
48
- # Let the parent class do its magic.
49
- super(klass, current_scope, opts)
50
- end
51
-
52
- # get the to_query value for this resource scope
53
- def to_hash
54
- # debugger
55
- if @params.count == 0
56
- scope_arguments = true
57
- else
58
- scope_arguments = {}
59
- @params.count.times do |i|
60
- scope_arguments[@params[i]] = @values[i] if @values[i] != nil
61
- end
62
- end
63
- self.parent_hash.merge({@name => scope_arguments})
64
- end
65
- end
66
- end
67
- end
68
-
@@ -1,16 +0,0 @@
1
- require 'api_resource/associations/multi_object_proxy'
2
- module ApiResource
3
- module Associations
4
- class HasManyRemoteObjectProxy < MultiObjectProxy
5
- def initialize(klass_name, contents, owner)
6
- super
7
- return if self.internal_object.present? || self.remote_path
8
- # now if we have an owner and a foreign key, we set the data up to load
9
- if owner
10
- self.load({"service_uri" => self.klass.collection_path(self.owner.class.to_s.foreign_key => self.owner.id)}.merge(self.klass.scopes))
11
- end
12
- true
13
- end
14
- end
15
- end
16
- end
@@ -1,13 +0,0 @@
1
- module ApiResource
2
- module Associations
3
- module HasManyThroughRemoteObjectProxy
4
- def has_many_through_remote(association, options)
5
- self.instance_eval do
6
- send(:define_method, association) do
7
- send(options[:through]).collect{ |t| t.send(association.to_s.singularize) }.flatten
8
- end
9
- end
10
- end
11
- end
12
- end
13
- end
@@ -1,24 +0,0 @@
1
- require 'api_resource/associations/single_object_proxy'
2
- module ApiResource
3
- module Associations
4
- class HasOneRemoteObjectProxy < SingleObjectProxy
5
- def initialize(klass_name, contents, owner)
6
- super
7
- return if self.internal_object
8
- # now if we have an owner and a foreign key, we set the data up to load
9
- if owner
10
- self.load({"service_uri" => self.klass.collection_path(self.owner.class.to_s.foreign_key => self.owner.id)}.merge(self.klass.scopes))
11
- end
12
- true
13
- end
14
- protected
15
- # load data from the remote server
16
- # In a has_one, we can get back an Array, so we use the first element
17
- def load_from_remote(options)
18
- data = super(options)
19
- data = data.first if data.is_a?(Array)
20
- data
21
- end
22
- end
23
- end
24
- end
@@ -1,15 +0,0 @@
1
- require 'api_resource/associations/dynamic_resource_scope'
2
-
3
- module ApiResource
4
- module Associations
5
- class MultiArgumentResourceScope < DynamicResourceScope
6
- # initialize with a variable number of dynamic arguments
7
- def initialize(klass, current_scope, *dynamic_value)
8
- # pull off opts
9
- opts = dynamic_value.extract_options!
10
- # we always dynamic value to be an Array, so we don't use the splat here
11
- super(klass, current_scope, dynamic_value.flatten, opts)
12
- end
13
- end
14
- end
15
- end
@@ -1,84 +0,0 @@
1
- require 'api_resource/associations/association_proxy'
2
-
3
- module ApiResource
4
-
5
- module Associations
6
-
7
- class MultiObjectProxy < AssociationProxy
8
-
9
- include Enumerable
10
-
11
- def all
12
- self.internal_object
13
- end
14
-
15
- def each(*args, &block)
16
- self.internal_object.each(*args, &block)
17
- end
18
-
19
- def ==(other)
20
- return false if self.class != other.class
21
- if self.internal_object.is_a?(Array)
22
- self.internal_object.sort.each_with_index do |elem, i|
23
- return false if other.internal_object.sort[i].attributes != elem.attributes
24
- end
25
- end
26
- return true
27
- end
28
-
29
- def serializable_hash(options)
30
- self.internal_object.collect{|obj| obj.serializable_hash(options) }
31
- end
32
-
33
- # force a load when calling this method
34
- def internal_object
35
- @internal_object ||= self.load_scope_with_options(:all, {})
36
- end
37
-
38
- def internal_object=(contents)
39
- return @internal_object = contents if contents.all?{|o| o.is_a?(self.klass)}
40
- return load(contents)
41
- end
42
-
43
- protected
44
- def load_scope_with_options(scope, options)
45
- scope = self.loaded_hash_key(scope.to_s, options)
46
- return [] if self.remote_path.blank?
47
-
48
- self.loaded[scope] ||= begin
49
- self.times_loaded += 1
50
- self.load_from_remote(options).collect{|item| self.klass.new(item)}
51
- end
52
-
53
- end
54
-
55
- def load(contents)
56
- @internal_object = [] and return nil if contents.blank?
57
- if contents.is_a?(Array) && contents.first.is_a?(Hash) && contents.first[self.class.remote_path_element]
58
- settings = contents.slice!(0).with_indifferent_access
59
- end
60
-
61
- settings = contents.with_indifferent_access if contents.is_a?(Hash)
62
- settings ||= {}.with_indifferent_access
63
-
64
- raise "Invalid response for multi object relationship: #{contents}" unless settings[self.class.remote_path_element] || contents.is_a?(Array)
65
- self.remote_path = settings.delete(self.class.remote_path_element)
66
-
67
- settings.each do |key, value|
68
- raise "Expected the scope #{key} to point to a hash, to #{value}" unless value.is_a?(Hash)
69
- self.instance_eval <<-EOE, __FILE__, __LINE__ + 1
70
- def #{key}(opts = {})
71
- @#{key} ||= ApiResource::Associations::RelationScope.new(self, :#{key}, opts)
72
- end
73
- EOE
74
- self.scopes[key.to_s] = value
75
- end
76
-
77
- # Create the internal object
78
- @internal_object = contents.is_a?(Array) ? contents.collect{|item| self.klass.new(item)} : nil
79
- end
80
- end
81
-
82
- end
83
-
84
- end
@@ -1,12 +0,0 @@
1
- module ApiResource
2
- module Associations
3
- # RelatedObjectHash, re-defines dup to be recursive
4
- class RelatedObjectHash < HashWithIndifferentAccess
5
- def dup
6
- Marshal.load(Marshal.dump(self))
7
- end
8
- # use this behavior for clone too
9
- alias_method :clone, :dup
10
- end
11
- end
12
- end
@@ -1,25 +0,0 @@
1
- require 'api_resource/associations/scope'
2
-
3
- module ApiResource
4
-
5
- module Associations
6
-
7
- class RelationScope < Scope
8
-
9
- # Use this method to access the internal data, this guarantees that loading only occurs once per object
10
- def internal_object
11
- ApiResource.with_ttl(ttl) do
12
- @internal_object ||= self.klass.send(:load_scope_with_options, self.current_scope, self.to_hash)
13
- end
14
- end
15
- #
16
- # class factory
17
- def self.class_factory(hsh)
18
- ApiResource::Associations::RelationScope
19
- end
20
-
21
- end
22
-
23
- end
24
-
25
- end
@@ -1,32 +0,0 @@
1
- require 'api_resource/associations/scope'
2
-
3
- module ApiResource
4
-
5
- module Associations
6
-
7
- class ResourceScope < Scope
8
-
9
- include Enumerable
10
-
11
- def internal_object
12
- ApiResource.with_ttl(ttl) do
13
- @internal_object ||= self.klass.send(:find, :all, :params => self.to_hash)
14
- end
15
- end
16
-
17
- alias_method :all, :internal_object
18
-
19
- def each(*args, &block)
20
- self.internal_object.each(*args, &block)
21
- end
22
-
23
- # Used by ApiResource::Scopes to create methods with the same name
24
- # as the scope
25
- #
26
- # Weird place to have a factory... could have been on Scope or a separate class...
27
- def self.class_factory(hsh)
28
- return ApiResource::Associations::GenericScope
29
- end
30
- end
31
- end
32
- end
@@ -1,132 +0,0 @@
1
- module ApiResource
2
-
3
- module Associations
4
-
5
- class Scope
6
-
7
- attr_accessor :klass, :current_scope, :internal_object
8
-
9
- attr_reader :scopes
10
-
11
- def initialize(klass, current_scope, opts = {})
12
- # Holds onto the association proxy this RelationScope is bound to
13
- @klass = klass
14
- @parent = opts.delete(:parent)
15
- @ttl = opts.delete(:expires_in)
16
- # splits on _and_ and sorts to get a consistent scope key order
17
- @current_scope = (self.parent_scope + Array.wrap(current_scope.to_s)).sort
18
- # define methods for the scopes of the object
19
-
20
- klass.scopes.each do |key, val|
21
- self.instance_eval <<-EOE, __FILE__, __LINE__ + 1
22
- # This class always has at least one scope, adding a new one should clone this object
23
- def #{key}(*args)
24
- obj = self.clone
25
- # Call reload to make it go back to the webserver the next time it loads
26
- obj.reload
27
- return obj.enhance_current_scope(:#{key}, *args)
28
- end
29
- EOE
30
- self.scopes[key.to_s] = val
31
- end
32
- # Use the method current scope because it gives a string
33
- # This expression substitutes the options from opts into the default attributes of the scope, it will only copy keys that exist in the original
34
- self.scopes[self.current_scope] = opts.inject(self.scopes[current_scope]){|accum,(k,v)| accum.key?(k.to_s) ? accum.merge(k.to_s => v) : accum}
35
- end
36
-
37
- def ttl
38
- @ttl || 0
39
- end
40
-
41
- # Use this method to access the internal data, this guarantees that loading only occurs once per object
42
- def internal_object
43
- raise "Not Implemented: This method must be implemented in a subclass"
44
- end
45
-
46
- def scopes
47
- @scopes ||= {}.with_indifferent_access
48
- end
49
-
50
- def scope?(scp)
51
- self.scopes.key?(scp.to_s)
52
- end
53
-
54
- def current_scope
55
- ActiveSupport::StringInquirer.new(@current_scope.join("_and_").concat("_scope"))
56
- end
57
-
58
- def to_hash
59
- self.parent_hash.merge(self.scopes[self.current_scope])
60
- end
61
-
62
- # takes empty hashes and replaces them with true so that to_query doesn't strip them out
63
- def to_query_safe_hash(hash)
64
- hash.each_pair do |k, v|
65
- hash[k] = to_query_safe_hash(v) if v.is_a?(Hash)
66
- hash[k] = true if v == {}
67
- end
68
- return hash
69
- end
70
-
71
- # gets the current hash and calls to_query on it
72
- def to_query
73
- #We need to add the unescape because to_query breaks on nested arrays
74
- CGI.unescape(to_query_safe_hash(self.to_hash).to_query)
75
- end
76
-
77
- def method_missing(method, *args, &block)
78
- self.internal_object.send(method, *args, &block)
79
- end
80
-
81
- def reload
82
- remove_instance_variable(:@internal_object) if instance_variable_defined?(:@internal_object)
83
- self
84
- end
85
-
86
- def to_s
87
- self.internal_object.to_s
88
- end
89
-
90
- def inspect
91
- self.internal_object.inspect
92
- end
93
-
94
- def blank?
95
- self.internal_object.blank?
96
- end
97
- alias_method :empty?, :blank?
98
-
99
- def present?
100
- self.internal_object.present?
101
- end
102
-
103
- def expires_in(ttl)
104
- ApiResource::Decorators::CachingDecorator.new(self, ttl)
105
- end
106
-
107
- protected
108
- # scope from the parent
109
- def parent_scope
110
- ret = @parent ? Array.wrap(@parent.current_scope).collect{|el| el.gsub(/_scope$/,'')} : []
111
- ret.collect{|el| el.split(/_and_/)}.flatten
112
- end
113
- # querystring hash from parent
114
- def parent_hash
115
- @parent ? @parent.to_hash : {}
116
- end
117
- def enhance_current_scope(scp, *args)
118
- opts = args.extract_options!
119
- check_scope(scp)
120
- cache_key = "a#{Digest::MD5.hexdigest((args.sort + [scp]).to_s)}"
121
- return instance_variable_get("@#{cache_key}") if instance_variable_defined?("@#{cache_key}")
122
- return instance_variable_set("@#{cache_key}", self.class.class_factory(self.scopes[scp]).new(self.klass, scp, *args, opts.merge(:parent => self)))
123
- end
124
- # make sure we have a valid scope
125
- def check_scope(scp)
126
- raise ArgumentError, "Unknown scope #{scp}" unless self.scope?(scp.to_s)
127
- end
128
- end
129
-
130
- end
131
-
132
- end