api_resource 0.4.0 → 0.4.1

Sign up to get free protection for your applications and to get access to all the features.
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