activeresource 3.2.22.5 → 5.1.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 (33) hide show
  1. checksums.yaml +5 -5
  2. data/MIT-LICENSE +2 -2
  3. data/README.rdoc +147 -49
  4. data/lib/active_resource.rb +12 -12
  5. data/lib/active_resource/active_job_serializer.rb +26 -0
  6. data/lib/active_resource/associations.rb +175 -0
  7. data/lib/active_resource/associations/builder/association.rb +33 -0
  8. data/lib/active_resource/associations/builder/belongs_to.rb +16 -0
  9. data/lib/active_resource/associations/builder/has_many.rb +14 -0
  10. data/lib/active_resource/associations/builder/has_one.rb +14 -0
  11. data/lib/active_resource/base.rb +444 -231
  12. data/lib/active_resource/callbacks.rb +22 -0
  13. data/lib/active_resource/collection.rb +94 -0
  14. data/lib/active_resource/connection.rb +112 -105
  15. data/lib/active_resource/custom_methods.rb +24 -14
  16. data/lib/active_resource/exceptions.rb +5 -3
  17. data/lib/active_resource/formats.rb +5 -3
  18. data/lib/active_resource/formats/json_format.rb +4 -1
  19. data/lib/active_resource/formats/xml_format.rb +4 -2
  20. data/lib/active_resource/http_mock.rb +69 -31
  21. data/lib/active_resource/log_subscriber.rb +14 -3
  22. data/lib/active_resource/observing.rb +0 -29
  23. data/lib/active_resource/railtie.rb +14 -3
  24. data/lib/active_resource/reflection.rb +78 -0
  25. data/lib/active_resource/schema.rb +4 -4
  26. data/lib/active_resource/singleton.rb +113 -0
  27. data/lib/active_resource/threadsafe_attributes.rb +66 -0
  28. data/lib/active_resource/validations.rb +56 -14
  29. data/lib/active_resource/version.rb +7 -5
  30. data/lib/activeresource.rb +3 -0
  31. metadata +78 -16
  32. data/CHANGELOG.md +0 -437
  33. data/examples/performance.rb +0 -70
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/class/attribute"
4
+ require "active_support/core_ext/module/deprecation"
5
+
6
+ module ActiveResource
7
+ # = Active Resource reflection
8
+ #
9
+ # Associations in ActiveResource would be used to resolve nested attributes
10
+ # in a response with correct classes.
11
+ # Now they could be specified over Associations with the options :class_name
12
+ module Reflection # :nodoc:
13
+ extend ActiveSupport::Concern
14
+
15
+ included do
16
+ class_attribute :reflections
17
+ self.reflections = {}
18
+ end
19
+
20
+ module ClassMethods
21
+ def create_reflection(macro, name, options)
22
+ reflection = AssociationReflection.new(macro, name, options)
23
+ self.reflections = self.reflections.merge(name => reflection)
24
+ reflection
25
+ end
26
+ end
27
+
28
+
29
+ class AssociationReflection
30
+ def initialize(macro, name, options)
31
+ @macro, @name, @options = macro, name, options
32
+ end
33
+
34
+ # Returns the name of the macro.
35
+ #
36
+ # <tt>has_many :clients</tt> returns <tt>:clients</tt>
37
+ attr_reader :name
38
+
39
+ # Returns the macro type.
40
+ #
41
+ # <tt>has_many :clients</tt> returns <tt>:has_many</tt>
42
+ attr_reader :macro
43
+
44
+ # Returns the hash of options used for the macro.
45
+ #
46
+ # <tt>has_many :clients</tt> returns +{}+
47
+ attr_reader :options
48
+
49
+ # Returns the class for the macro.
50
+ #
51
+ # <tt>has_many :clients</tt> returns the Client class
52
+ def klass
53
+ @klass ||= class_name.constantize
54
+ end
55
+
56
+ # Returns the class name for the macro.
57
+ #
58
+ # <tt>has_many :clients</tt> returns <tt>'Client'</tt>
59
+ def class_name
60
+ @class_name ||= derive_class_name
61
+ end
62
+
63
+ # Returns the foreign_key for the macro.
64
+ def foreign_key
65
+ @foreign_key ||= self.options[:foreign_key] || "#{self.name.to_s.downcase}_id"
66
+ end
67
+
68
+ private
69
+ def derive_class_name
70
+ (options[:class_name] ? options[:class_name].to_s.camelize : name.to_s.classify)
71
+ end
72
+
73
+ def derive_foreign_key
74
+ options[:foreign_key] ? options[:foreign_key].to_s : "#{name.to_s.downcase}_id"
75
+ end
76
+ end
77
+ end
78
+ end
@@ -1,4 +1,4 @@
1
- require 'active_resource/exceptions'
1
+ # frozen_string_literal: true
2
2
 
3
3
  module ActiveResource # :nodoc:
4
4
  class Schema # :nodoc:
@@ -31,8 +31,8 @@ module ActiveResource # :nodoc:
31
31
 
32
32
  the_type = type.to_s
33
33
  # TODO: add defaults
34
- #the_attr = [type.to_s]
35
- #the_attr << options[:default] if options.has_key? :default
34
+ # the_attr = [type.to_s]
35
+ # the_attr << options[:default] if options.has_key? :default
36
36
  @attrs[name.to_s] = the_type
37
37
  self
38
38
  end
@@ -47,7 +47,7 @@ module ActiveResource # :nodoc:
47
47
  # attr_names.each { |name| attribute(name, 'string', options) }
48
48
  # end
49
49
  class_eval <<-EOV, __FILE__, __LINE__ + 1
50
- def #{attr_type.to_s}(*args)
50
+ def #{attr_type}(*args)
51
51
  options = args.extract_options!
52
52
  attr_names = args
53
53
 
@@ -0,0 +1,113 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveResource
4
+ module Singleton
5
+ extend ActiveSupport::Concern
6
+
7
+ module ClassMethods
8
+ attr_writer :singleton_name
9
+
10
+ def singleton_name
11
+ @singleton_name ||= model_name.element
12
+ end
13
+
14
+ # Gets the singleton path for the object. If the +query_options+ parameter is omitted, Rails
15
+ # will split from the \prefix options.
16
+ #
17
+ # ==== Options
18
+ # * +prefix_options+ - A \hash to add a \prefix to the request for nested URLs (e.g., <tt>:account_id => 19</tt>
19
+ # would yield a URL like <tt>/accounts/19/purchases.json</tt>).
20
+ #
21
+ # * +query_options+ - A \hash to add items to the query string for the request.
22
+ #
23
+ # ==== Examples
24
+ # Weather.singleton_path
25
+ # # => /weather.json
26
+ #
27
+ # class Inventory < ActiveResource::Base
28
+ # self.site = "https://37s.sunrise.com"
29
+ # self.prefix = "/products/:product_id/"
30
+ # end
31
+ #
32
+ # Inventory.singleton_path(:product_id => 5)
33
+ # # => /products/5/inventory.json
34
+ #
35
+ # Inventory.singleton_path({:product_id => 5}, {:sold => true})
36
+ # # => /products/5/inventory.json?sold=true
37
+ #
38
+ def singleton_path(prefix_options = {}, query_options = nil)
39
+ check_prefix_options(prefix_options)
40
+
41
+ prefix_options, query_options = split_options(prefix_options) if query_options.nil?
42
+ "#{prefix(prefix_options)}#{singleton_name}#{format_extension}#{query_string(query_options)}"
43
+ end
44
+
45
+ # Core method for finding singleton resources.
46
+ #
47
+ # ==== Arguments
48
+ # Takes a single argument of options
49
+ #
50
+ # ==== Options
51
+ # * <tt>:params</tt> - Sets the query and \prefix (nested URL) parameters.
52
+ #
53
+ # ==== Examples
54
+ # Weather.find
55
+ # # => GET /weather.json
56
+ #
57
+ # Weather.find(:params => {:degrees => 'fahrenheit'})
58
+ # # => GET /weather.json?degrees=fahrenheit
59
+ #
60
+ # == Failure or missing data
61
+ # A failure to find the requested object raises a ResourceNotFound exception.
62
+ #
63
+ # Inventory.find
64
+ # # => raises ResourceNotFound
65
+ def find(options = {})
66
+ find_singleton(options)
67
+ end
68
+
69
+ private
70
+ # Find singleton resource
71
+ def find_singleton(options)
72
+ prefix_options, query_options = split_options(options[:params])
73
+
74
+ path = singleton_path(prefix_options, query_options)
75
+ resp = self.format.decode(self.connection.get(path, self.headers).body)
76
+ instantiate_record(resp, prefix_options)
77
+ end
78
+ end
79
+ # Deletes the resource from the remote service.
80
+ #
81
+ # ==== Examples
82
+ # weather = Weather.find
83
+ # weather.destroy
84
+ # Weather.find # 404 (Resource Not Found)
85
+ def destroy
86
+ connection.delete(singleton_path, self.class.headers)
87
+ end
88
+
89
+
90
+ protected
91
+
92
+ # Update the resource on the remote service
93
+ def update
94
+ connection.put(singleton_path(prefix_options), encode, self.class.headers).tap do |response|
95
+ load_attributes_from_response(response)
96
+ end
97
+ end
98
+
99
+ # Create (i.e. \save to the remote service) the \new resource.
100
+ def create
101
+ connection.post(singleton_path, encode, self.class.headers).tap do |response|
102
+ self.id = id_from_response(response)
103
+ load_attributes_from_response(response)
104
+ end
105
+ end
106
+
107
+ private
108
+
109
+ def singleton_path(options = nil)
110
+ self.class.singleton_path(options || prefix_options)
111
+ end
112
+ end
113
+ end
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/object/duplicable"
4
+
5
+ module ThreadsafeAttributes
6
+ def self.included(klass)
7
+ klass.extend(ClassMethods)
8
+ end
9
+
10
+ module ClassMethods
11
+ def threadsafe_attribute(*attrs)
12
+ main_thread = Thread.main # remember this, because it could change after forking
13
+
14
+ attrs.each do |attr|
15
+ define_method attr do
16
+ get_threadsafe_attribute(attr, main_thread)
17
+ end
18
+
19
+ define_method "#{attr}=" do |value|
20
+ set_threadsafe_attribute(attr, value, main_thread)
21
+ end
22
+
23
+ define_method "#{attr}_defined?" do
24
+ threadsafe_attribute_defined?(attr, main_thread)
25
+ end
26
+ end
27
+ end
28
+ end
29
+
30
+ private
31
+
32
+ def get_threadsafe_attribute(name, main_thread)
33
+ if threadsafe_attribute_defined_by_thread?(name, Thread.current)
34
+ get_threadsafe_attribute_by_thread(name, Thread.current)
35
+ elsif threadsafe_attribute_defined_by_thread?(name, main_thread)
36
+ value = get_threadsafe_attribute_by_thread(name, main_thread)
37
+ value = value.dup if value.duplicable?
38
+ set_threadsafe_attribute_by_thread(name, value, Thread.current)
39
+ value
40
+ end
41
+ end
42
+
43
+ def set_threadsafe_attribute(name, value, main_thread)
44
+ set_threadsafe_attribute_by_thread(name, value, Thread.current)
45
+ unless threadsafe_attribute_defined_by_thread?(name, main_thread)
46
+ set_threadsafe_attribute_by_thread(name, value, main_thread)
47
+ end
48
+ end
49
+
50
+ def threadsafe_attribute_defined?(name, main_thread)
51
+ threadsafe_attribute_defined_by_thread?(name, Thread.current) || ((Thread.current != main_thread) && threadsafe_attribute_defined_by_thread?(name, main_thread))
52
+ end
53
+
54
+ def get_threadsafe_attribute_by_thread(name, thread)
55
+ thread.thread_variable_get "active.resource.#{name}.#{self.object_id}"
56
+ end
57
+
58
+ def set_threadsafe_attribute_by_thread(name, value, thread)
59
+ thread.thread_variable_set "active.resource.#{name}.#{self.object_id}.defined", true
60
+ thread.thread_variable_set "active.resource.#{name}.#{self.object_id}", value
61
+ end
62
+
63
+ def threadsafe_attribute_defined_by_thread?(name, thread)
64
+ thread.thread_variable_get "active.resource.#{name}.#{self.object_id}.defined"
65
+ end
66
+ end
@@ -1,5 +1,7 @@
1
- require 'active_support/core_ext/array/wrap'
2
- require 'active_support/core_ext/object/blank'
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/array/wrap"
4
+ require "active_support/core_ext/object/blank"
3
5
 
4
6
  module ActiveResource
5
7
  class ResourceInvalid < ClientError #:nodoc:
@@ -13,27 +15,64 @@ module ActiveResource
13
15
  # or not (by passing true).
14
16
  def from_array(messages, save_cache = false)
15
17
  clear unless save_cache
16
- humanized_attributes = Hash[@base.attributes.keys.map { |attr_name| [attr_name.humanize, attr_name] }]
18
+ humanized_attributes = Hash[@base.known_attributes.map { |attr_name| [attr_name.humanize, attr_name] }]
17
19
  messages.each do |message|
18
- attr_message = humanized_attributes.keys.detect do |attr_name|
20
+ attr_message = humanized_attributes.keys.sort_by { |a| -a.length }.detect do |attr_name|
19
21
  if message[0, attr_name.size + 1] == "#{attr_name} "
20
22
  add humanized_attributes[attr_name], message[(attr_name.size + 1)..-1]
21
23
  end
22
24
  end
23
-
24
25
  self[:base] << message if attr_message.nil?
25
26
  end
26
27
  end
27
28
 
29
+ # Grabs errors from a hash of attribute => array of errors elements
30
+ # The second parameter directs the errors cache to be cleared (default)
31
+ # or not (by passing true)
32
+ #
33
+ # Unrecognized attribute names will be humanized and added to the record's
34
+ # base errors.
35
+ def from_hash(messages, save_cache = false)
36
+ clear unless save_cache
37
+
38
+ messages.each do |(key, errors)|
39
+ errors.each do |error|
40
+ if @base.known_attributes.include?(key)
41
+ add key, error
42
+ elsif key == "base"
43
+ self[:base] << error
44
+ else
45
+ # reporting an error on an attribute not in attributes
46
+ # format and add them to base
47
+ self[:base] << "#{key.humanize} #{error}"
48
+ end
49
+ end
50
+ end
51
+ end
52
+
28
53
  # Grabs errors from a json response.
29
54
  def from_json(json, save_cache = false)
30
- array = Array.wrap(ActiveSupport::JSON.decode(json)['errors']) rescue []
31
- from_array array, save_cache
55
+ decoded = ActiveSupport::JSON.decode(json) || {} rescue {}
56
+ if decoded.kind_of?(Hash) && (decoded.has_key?("errors") || decoded.empty?)
57
+ errors = decoded["errors"] || {}
58
+ if errors.kind_of?(Array)
59
+ # 3.2.1-style with array of strings
60
+ ActiveSupport::Deprecation.warn("Returning errors as an array of strings is deprecated.")
61
+ from_array errors, save_cache
62
+ else
63
+ # 3.2.2+ style
64
+ from_hash errors, save_cache
65
+ end
66
+ else
67
+ # <3.2-style respond_with - lacks 'errors' key
68
+ ActiveSupport::Deprecation.warn('Returning errors as a hash without a root "errors" key is deprecated.')
69
+ from_hash decoded, save_cache
70
+ end
32
71
  end
33
72
 
34
73
  # Grabs errors from an XML response.
35
74
  def from_xml(xml, save_cache = false)
36
- array = Array.wrap(Hash.from_xml(xml)['errors']['error']) rescue []
75
+ array = Array.wrap(Hash.from_xml(xml)["errors"]["error"]) rescue []
37
76
  from_array array, save_cache
38
77
  end
39
78
  end
@@ -63,12 +102,13 @@ module ActiveResource
63
102
  include ActiveModel::Validations
64
103
 
65
104
  included do
66
- alias_method_chain :save, :validation
105
+ alias_method :save_without_validation, :save
106
+ alias_method :save, :save_with_validation
67
107
  end
68
108
 
69
109
  # Validate a resource and save (POST) it to the remote web service.
70
110
  # If any local validations fail - the save (POST) will not be attempted.
71
- def save_with_validation(options={})
111
+ def save_with_validation(options = {})
72
112
  perform_validation = options[:validate] != false
73
113
 
74
114
  # clear the remote validations so they don't interfere with the local
@@ -93,7 +133,7 @@ module ActiveResource
93
133
 
94
134
  # Loads the set of remote errors into the object's Errors based on the
95
135
  # content-type of the error-block received.
96
- def load_remote_errors(remote_errors, save_cache = false ) #:nodoc:
136
+ def load_remote_errors(remote_errors, save_cache = false) #:nodoc:
97
137
  case self.class.format
98
138
  when ActiveResource::Formats[:xml]
99
139
  errors.from_xml(remote_errors.response.body, save_cache)
@@ -121,9 +161,11 @@ module ActiveResource
121
161
  # # => false
122
162
  #
123
163
  def valid?
124
- super
125
- load_remote_errors(@remote_errors, true) if defined?(@remote_errors) && @remote_errors.present?
126
- errors.empty?
164
+ run_callbacks :validate do
165
+ super
166
+ load_remote_errors(@remote_errors, true) if defined?(@remote_errors) && @remote_errors.present?
167
+ errors.empty?
168
+ end
127
169
  end
128
170
 
129
171
  # Returns the Errors object that holds all information about attribute error messages.
@@ -1,10 +1,12 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveResource
2
4
  module VERSION #:nodoc:
3
- MAJOR = 3
4
- MINOR = 2
5
- TINY = 22
6
- PRE = "5"
5
+ MAJOR = 5
6
+ MINOR = 1
7
+ TINY = 1
8
+ PRE = nil
7
9
 
8
- STRING = [MAJOR, MINOR, TINY, PRE].compact.join('.')
10
+ STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
9
11
  end
10
12
  end
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_resource"
metadata CHANGED
@@ -1,43 +1,97 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activeresource
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.2.22.5
4
+ version: 5.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Heinemeier Hansson
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-09-14 00:00:00.000000000 Z
11
+ date: 2020-05-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - '='
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: 3.2.22.5
19
+ version: '5.0'
20
+ - - "<"
21
+ - !ruby/object:Gem::Version
22
+ version: '7'
20
23
  type: :runtime
21
24
  prerelease: false
22
25
  version_requirements: !ruby/object:Gem::Requirement
23
26
  requirements:
24
- - - '='
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ version: '5.0'
30
+ - - "<"
25
31
  - !ruby/object:Gem::Version
26
- version: 3.2.22.5
32
+ version: '7'
27
33
  - !ruby/object:Gem::Dependency
28
34
  name: activemodel
29
35
  requirement: !ruby/object:Gem::Requirement
30
36
  requirements:
31
- - - '='
37
+ - - ">="
32
38
  - !ruby/object:Gem::Version
33
- version: 3.2.22.5
39
+ version: '5.0'
40
+ - - "<"
41
+ - !ruby/object:Gem::Version
42
+ version: '7'
34
43
  type: :runtime
35
44
  prerelease: false
36
45
  version_requirements: !ruby/object:Gem::Requirement
37
46
  requirements:
38
- - - '='
47
+ - - ">="
48
+ - !ruby/object:Gem::Version
49
+ version: '5.0'
50
+ - - "<"
51
+ - !ruby/object:Gem::Version
52
+ version: '7'
53
+ - !ruby/object:Gem::Dependency
54
+ name: activemodel-serializers-xml
55
+ requirement: !ruby/object:Gem::Requirement
56
+ requirements:
57
+ - - "~>"
58
+ - !ruby/object:Gem::Version
59
+ version: '1.0'
60
+ type: :runtime
61
+ prerelease: false
62
+ version_requirements: !ruby/object:Gem::Requirement
63
+ requirements:
64
+ - - "~>"
65
+ - !ruby/object:Gem::Version
66
+ version: '1.0'
67
+ - !ruby/object:Gem::Dependency
68
+ name: rake
69
+ requirement: !ruby/object:Gem::Requirement
70
+ requirements:
71
+ - - ">="
72
+ - !ruby/object:Gem::Version
73
+ version: '0'
74
+ type: :development
75
+ prerelease: false
76
+ version_requirements: !ruby/object:Gem::Requirement
77
+ requirements:
78
+ - - ">="
79
+ - !ruby/object:Gem::Version
80
+ version: '0'
81
+ - !ruby/object:Gem::Dependency
82
+ name: mocha
83
+ requirement: !ruby/object:Gem::Requirement
84
+ requirements:
85
+ - - ">="
86
+ - !ruby/object:Gem::Version
87
+ version: 0.13.0
88
+ type: :development
89
+ prerelease: false
90
+ version_requirements: !ruby/object:Gem::Requirement
91
+ requirements:
92
+ - - ">="
39
93
  - !ruby/object:Gem::Version
40
- version: 3.2.22.5
94
+ version: 0.13.0
41
95
  description: REST on Rails. Wrap your RESTful web app with Ruby classes and work with
42
96
  them like Active Record models.
43
97
  email: david@loudthinking.com
@@ -46,12 +100,18 @@ extensions: []
46
100
  extra_rdoc_files:
47
101
  - README.rdoc
48
102
  files:
49
- - CHANGELOG.md
50
103
  - MIT-LICENSE
51
104
  - README.rdoc
52
- - examples/performance.rb
53
105
  - lib/active_resource.rb
106
+ - lib/active_resource/active_job_serializer.rb
107
+ - lib/active_resource/associations.rb
108
+ - lib/active_resource/associations/builder/association.rb
109
+ - lib/active_resource/associations/builder/belongs_to.rb
110
+ - lib/active_resource/associations/builder/has_many.rb
111
+ - lib/active_resource/associations/builder/has_one.rb
54
112
  - lib/active_resource/base.rb
113
+ - lib/active_resource/callbacks.rb
114
+ - lib/active_resource/collection.rb
55
115
  - lib/active_resource/connection.rb
56
116
  - lib/active_resource/custom_methods.rb
57
117
  - lib/active_resource/exceptions.rb
@@ -62,9 +122,13 @@ files:
62
122
  - lib/active_resource/log_subscriber.rb
63
123
  - lib/active_resource/observing.rb
64
124
  - lib/active_resource/railtie.rb
125
+ - lib/active_resource/reflection.rb
65
126
  - lib/active_resource/schema.rb
127
+ - lib/active_resource/singleton.rb
128
+ - lib/active_resource/threadsafe_attributes.rb
66
129
  - lib/active_resource/validations.rb
67
130
  - lib/active_resource/version.rb
131
+ - lib/activeresource.rb
68
132
  homepage: http://www.rubyonrails.org
69
133
  licenses:
70
134
  - MIT
@@ -79,17 +143,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
79
143
  requirements:
80
144
  - - ">="
81
145
  - !ruby/object:Gem::Version
82
- version: 1.8.7
146
+ version: 2.2.2
83
147
  required_rubygems_version: !ruby/object:Gem::Requirement
84
148
  requirements:
85
149
  - - ">="
86
150
  - !ruby/object:Gem::Version
87
151
  version: '0'
88
152
  requirements: []
89
- rubyforge_project:
90
- rubygems_version: 2.6.6
153
+ rubygems_version: 3.2.0.pre1
91
154
  signing_key:
92
155
  specification_version: 4
93
156
  summary: REST modeling framework (part of Rails).
94
157
  test_files: []
95
- has_rdoc: