activeresource 4.0.0 → 4.1.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of activeresource might be problematic. Click here for more details.

checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 82b2154f86c57749c08bad97d435fcb1cdde0408
4
- data.tar.gz: 1c514b63dc4ea568665f161079adff26d9cdb611
3
+ metadata.gz: 5ec4c5f35bfca437beeae8e7acb8763bc0ce1f96
4
+ data.tar.gz: 9ce68f2e6a206530f05c57ce23aaa0f240bc74f8
5
5
  SHA512:
6
- metadata.gz: 477756e26f0d705234fd0c1d7511d0850e569691ccb8bdbb8974fec70445e10d6d607cc852b2652e1a6335baf1b3400f23380b392c1fc203346f2344eb503326
7
- data.tar.gz: ccad2db0464de0b474d4d3dc1a36d1b86aa19d2ad20c6b68b5fe6170b4663567c07d445b8a1c0811e384fca02637f1f0631af0cf1e5b2842f86ebbad88d1c6f6
6
+ metadata.gz: e8faca6d64850e4eb46e54d829c90355b7d18538b618032498e747dd27fc12861fac7e5e0d5ba53f4bf7eb7203f85c2dd092f0ad1a3badc3ed290a958558e820
7
+ data.tar.gz: 23fd61de41602794182b27df1703ae3e7a82dba3249c285524f6a5d681b792b9ea38ab782d1a4731b8ddf7a09eb3b78acf5ce0ea04cca8bf0f2d573129da1a9f
@@ -1,4 +1,4 @@
1
- = Active Resource {<img src="https://secure.travis-ci.org/rails/activeresource.png" />}[http://travis-ci.org/rails/activeresource]
1
+ = Active Resource
2
2
 
3
3
  Active Resource (ARes) connects business objects and Representational State Transfer (REST)
4
4
  web services. It implements object-relational mapping for REST web services to provide transparent
@@ -28,7 +28,7 @@ The latest version of Active Resource can be installed with RubyGems:
28
28
 
29
29
  Or added to a Gemfile:
30
30
 
31
- gem 'activeresource', :require => 'active_resource'
31
+ gem 'activeresource'
32
32
 
33
33
  Source code can be downloaded on GitHub
34
34
 
@@ -119,10 +119,12 @@ a 'Location' header in the response with the RESTful URL location of the newly c
119
119
  id of the newly created resource is parsed out of the Location response header and automatically set
120
120
  as the id of the ARes object.
121
121
 
122
- # {"person":{"first":"Tyler","last":"Durden"}}
122
+ # {"first":"Tyler","last":"Durden"}
123
123
  #
124
124
  # is submitted as the body on
125
125
  #
126
+ # if include_root_in_json is set to true => {"person":{"first":"Tyler"}}
127
+ #
126
128
  # POST http://api.people.com:3000/people.json
127
129
  #
128
130
  # when save is called on a new Person object. An empty response is
@@ -142,10 +144,12 @@ as the id of the ARes object.
142
144
  with the exception that no response headers are needed -- just an empty response when the update on the
143
145
  server side was successful.
144
146
 
145
- # {"person":{"first":"Tyler"}}
147
+ # {"first":"Tyler"}
146
148
  #
147
149
  # is submitted as the body on
148
150
  #
151
+ # if include_root_in_json is set to true => {"person":{"first":"Tyler"}}
152
+ #
149
153
  # PUT http://api.people.com:3000/people/1.json
150
154
  #
151
155
  # when save is called on an existing Person object. An empty response is
@@ -207,11 +211,18 @@ Active Resource is released under the MIT license:
207
211
 
208
212
  * http://www.opensource.org/licenses/MIT
209
213
 
214
+ == Contributing to Active Resource
215
+
216
+ Active Resource is work of many contributors. You're encouraged to submit pull requests, propose
217
+ features and discuss issues.
218
+
219
+ See {CONTRIBUTING}[https://github.com/rails/activeresource/blob/master/CONTRIBUTING.md].
220
+
210
221
  == Support
211
222
 
212
223
  API documentation is at
213
224
 
214
- * http://api.rubyonrails.org
225
+ * http://rubydoc.info/gems/activeresource/4.0.0/frames
215
226
 
216
227
  Bug reports and feature requests can be filed with the rest for the Ruby on Rails project here:
217
228
 
@@ -41,3 +41,6 @@ module ActiveResource
41
41
  autoload :Validations
42
42
  autoload :Collection
43
43
  end
44
+
45
+ require 'active_resource/railtie' if defined? Rails
46
+
@@ -14,7 +14,7 @@ module ActiveResource::Associations
14
14
  # === Options
15
15
  # [:class_name]
16
16
  # Specify the class name of the association. This class name would
17
- # be used for resolving the association class.
17
+ # be used for resolving the association class.
18
18
  #
19
19
  # ==== Example for [:class_name] - option
20
20
  # GET /posts/123.json delivers following response body:
@@ -48,7 +48,7 @@ module ActiveResource::Associations
48
48
  # === Options
49
49
  # [:class_name]
50
50
  # Specify the class name of the association. This class name would
51
- # be used for resolving the association class.
51
+ # be used for resolving the association class.
52
52
  #
53
53
  # ==== Example for [:class_name] - option
54
54
  # GET /posts/1.json delivers following response body:
@@ -67,14 +67,14 @@ module ActiveResource::Associations
67
67
  # If the response body does not contain an attribute matching the association name
68
68
  # a request is sent to a singelton path under the current resource.
69
69
  # For example, if a Product class <tt>has_one :inventory</tt> calling <tt>Product#inventory</tt>
70
- # will generate a request on /product/:product_id/inventory.json.
70
+ # will generate a request on /products/:product_id/inventory.json.
71
71
  #
72
72
  def has_one(name, options = {})
73
73
  Builder::HasOne.build(self, name, options)
74
74
  end
75
75
 
76
76
  # Specifies a one-to-one association with another class. This class should only be used
77
- # if this class contains the foreign key.
77
+ # if this class contains the foreign key.
78
78
  #
79
79
  # Methods will be added for retrieval and query for a single associated object, for which
80
80
  # this object holds an id:
@@ -83,7 +83,7 @@ module ActiveResource::Associations
83
83
  # Returns the associated object. +nil+ is returned if the foreign key is +nil+.
84
84
  # Throws a ActiveResource::ResourceNotFound exception if the foreign key is not +nil+
85
85
  # and the resource is not found.
86
- #
86
+ #
87
87
  # (+association+ is replaced with the symbol passed as the first argument, so
88
88
  # <tt>belongs_to :post</tt> would add among others <tt>post.nil?</tt>.
89
89
  #
@@ -130,8 +130,8 @@ module ActiveResource::Associations
130
130
  instance_variable_get(ivar_name)
131
131
  elsif attributes.include?(method_name)
132
132
  attributes[method_name]
133
- else
134
- instance_variable_set(ivar_name, association_model.find(send(finder_key)))
133
+ elsif association_id = send(finder_key)
134
+ instance_variable_set(ivar_name, association_model.find(association_id))
135
135
  end
136
136
  end
137
137
  end
@@ -144,12 +144,14 @@ module ActiveResource::Associations
144
144
  instance_variable_get(ivar_name)
145
145
  elsif attributes.include?(method_name)
146
146
  attributes[method_name]
147
- else
147
+ elsif !new_record?
148
148
  instance_variable_set(ivar_name, association_model.find(:all, :params => {:"#{self.class.element_name}_id" => self.id}))
149
+ else
150
+ instance_variable_set(ivar_name, self.class.collection_parser.new)
149
151
  end
150
152
  end
151
153
  end
152
-
154
+
153
155
  # Defines the has_one association
154
156
  def defines_has_one_finder_method(method_name, association_model)
155
157
  ivar_name = :"@#{method_name}"
@@ -159,8 +161,10 @@ module ActiveResource::Associations
159
161
  instance_variable_get(ivar_name)
160
162
  elsif attributes.include?(method_name)
161
163
  attributes[method_name]
162
- else
164
+ elsif association_model.respond_to?(:singleton_name)
163
165
  instance_variable_set(ivar_name, association_model.find(:params => {:"#{self.class.element_name}_id" => self.id}))
166
+ else
167
+ instance_variable_set(ivar_name, association_model.find(:one, :from => "/#{self.class.collection_name}/#{self.id}/#{method_name}#{self.class.format_extension}"))
164
168
  end
165
169
  end
166
170
  end
@@ -18,6 +18,7 @@ require 'active_resource/schema'
18
18
  require 'active_resource/log_subscriber'
19
19
  require 'active_resource/associations'
20
20
  require 'active_resource/reflection'
21
+ require 'active_resource/threadsafe_attributes'
21
22
 
22
23
  module ActiveResource
23
24
  # ActiveResource::Base is the main class for mapping RESTful resources as models in a Rails application.
@@ -283,6 +284,16 @@ module ActiveResource
283
284
  # Internally, Active Resource relies on Ruby's Net::HTTP library to make HTTP requests. Setting +timeout+
284
285
  # sets the <tt>read_timeout</tt> of the internal Net::HTTP instance to the same value. The default
285
286
  # <tt>read_timeout</tt> is 60 seconds on most Ruby implementations.
287
+ #
288
+ # Active Resource also supports distinct +open_timeout+ (time to connect) and +read_timeout+ (how long to
289
+ # wait for an upstream response). This is inline with supported +Net::HTTP+ timeout configuration and allows
290
+ # for finer control of client timeouts depending on context.
291
+ #
292
+ # class Person < ActiveResource::Base
293
+ # self.site = "https://api.people.com"
294
+ # self.open_timeout = 2
295
+ # self.read_timeout = 10
296
+ # end
286
297
  class Base
287
298
  ##
288
299
  # :singleton-method:
@@ -294,7 +305,11 @@ module ActiveResource
294
305
  class_attribute :include_format_in_path
295
306
  self.include_format_in_path = true
296
307
 
308
+
297
309
  class << self
310
+ include ThreadsafeAttributes
311
+ threadsafe_attribute :_headers, :_connection, :_user, :_password, :_site, :_proxy
312
+
298
313
  # Creates a schema for this resource - setting the attributes that are
299
314
  # known prior to fetching an instance from the remote system.
300
315
  #
@@ -339,7 +354,7 @@ module ActiveResource
339
354
  #
340
355
  # p.num_children # => NoMethodError
341
356
  #
342
- # Attribute-types must be one of: <tt>string, integer, float</tt>
357
+ # Attribute-types must be one of: <tt>string, text, integer, float, decimal, datetime, timestamp, time, date, binary, boolean</tt>
343
358
  #
344
359
  # Note: at present the attribute-type doesn't do anything, but stay
345
360
  # tuned...
@@ -431,8 +446,8 @@ module ActiveResource
431
446
  # Subclass.site # => 'https://anonymous@test.com'
432
447
  # Subclass.site.user = 'david' # => TypeError: can't modify frozen object
433
448
  #
434
- if defined?(@site)
435
- @site
449
+ if _site_defined?
450
+ _site
436
451
  elsif superclass != Object && superclass.site
437
452
  superclass.site.dup.freeze
438
453
  end
@@ -441,21 +456,21 @@ module ActiveResource
441
456
  # Sets the URI of the REST resources to map for this class to the value in the +site+ argument.
442
457
  # The site variable is required for Active Resource's mapping to work.
443
458
  def site=(site)
444
- @connection = nil
459
+ self._connection = nil
445
460
  if site.nil?
446
- @site = nil
461
+ self._site = nil
447
462
  else
448
- @site = create_site_uri_from(site)
449
- @user = URI.parser.unescape(@site.user) if @site.user
450
- @password = URI.parser.unescape(@site.password) if @site.password
463
+ self._site = create_site_uri_from(site)
464
+ self._user = URI.parser.unescape(_site.user) if _site.user
465
+ self._password = URI.parser.unescape(_site.password) if _site.password
451
466
  end
452
467
  end
453
468
 
454
469
  # Gets the \proxy variable if a proxy is required
455
470
  def proxy
456
471
  # Not using superclass_delegating_reader. See +site+ for explanation
457
- if defined?(@proxy)
458
- @proxy
472
+ if _proxy_defined?
473
+ _proxy
459
474
  elsif superclass != Object && superclass.proxy
460
475
  superclass.proxy.dup.freeze
461
476
  end
@@ -463,15 +478,15 @@ module ActiveResource
463
478
 
464
479
  # Sets the URI of the http proxy to the value in the +proxy+ argument.
465
480
  def proxy=(proxy)
466
- @connection = nil
467
- @proxy = proxy.nil? ? nil : create_proxy_uri_from(proxy)
481
+ self._connection = nil
482
+ self._proxy = proxy.nil? ? nil : create_proxy_uri_from(proxy)
468
483
  end
469
484
 
470
485
  # Gets the \user for REST HTTP authentication.
471
486
  def user
472
487
  # Not using superclass_delegating_reader. See +site+ for explanation
473
- if defined?(@user)
474
- @user
488
+ if _user_defined?
489
+ _user
475
490
  elsif superclass != Object && superclass.user
476
491
  superclass.user.dup.freeze
477
492
  end
@@ -479,15 +494,15 @@ module ActiveResource
479
494
 
480
495
  # Sets the \user for REST HTTP authentication.
481
496
  def user=(user)
482
- @connection = nil
483
- @user = user
497
+ self._connection = nil
498
+ self._user = user
484
499
  end
485
500
 
486
501
  # Gets the \password for REST HTTP authentication.
487
502
  def password
488
503
  # Not using superclass_delegating_reader. See +site+ for explanation
489
- if defined?(@password)
490
- @password
504
+ if _password_defined?
505
+ _password
491
506
  elsif superclass != Object && superclass.password
492
507
  superclass.password.dup.freeze
493
508
  end
@@ -495,8 +510,8 @@ module ActiveResource
495
510
 
496
511
  # Sets the \password for REST HTTP authentication.
497
512
  def password=(password)
498
- @connection = nil
499
- @password = password
513
+ self._connection = nil
514
+ self._password = password
500
515
  end
501
516
 
502
517
  def auth_type
@@ -506,7 +521,7 @@ module ActiveResource
506
521
  end
507
522
 
508
523
  def auth_type=(auth_type)
509
- @connection = nil
524
+ self._connection = nil
510
525
  @auth_type = auth_type
511
526
  end
512
527
 
@@ -544,10 +559,22 @@ module ActiveResource
544
559
 
545
560
  # Sets the number of seconds after which requests to the REST API should time out.
546
561
  def timeout=(timeout)
547
- @connection = nil
562
+ self._connection = nil
548
563
  @timeout = timeout
549
564
  end
550
565
 
566
+ # Sets the number of seconds after which connection attempts to the REST API should time out.
567
+ def open_timeout=(timeout)
568
+ self._connection = nil
569
+ @open_timeout = timeout
570
+ end
571
+
572
+ # Sets the number of seconds after which reads to the REST API should time out.
573
+ def read_timeout=(timeout)
574
+ self._connection = nil
575
+ @read_timeout = timeout
576
+ end
577
+
551
578
  # Gets the number of seconds after which requests to the REST API should time out.
552
579
  def timeout
553
580
  if defined?(@timeout)
@@ -557,6 +584,24 @@ module ActiveResource
557
584
  end
558
585
  end
559
586
 
587
+ # Gets the number of seconds after which connection attempts to the REST API should time out.
588
+ def open_timeout
589
+ if defined?(@open_timeout)
590
+ @open_timeout
591
+ elsif superclass != Object && superclass.open_timeout
592
+ superclass.open_timeout
593
+ end
594
+ end
595
+
596
+ # Gets the number of seconds after which reads to the REST API should time out.
597
+ def read_timeout
598
+ if defined?(@read_timeout)
599
+ @read_timeout
600
+ elsif superclass != Object && superclass.read_timeout
601
+ superclass.read_timeout
602
+ end
603
+ end
604
+
560
605
  # Options that will get applied to an SSL connection.
561
606
  #
562
607
  # * <tt>:key</tt> - An OpenSSL::PKey::RSA or OpenSSL::PKey::DSA object.
@@ -569,7 +614,7 @@ module ActiveResource
569
614
  # * <tt>:cert_store</tt> - OpenSSL::X509::Store to verify peer certificate.
570
615
  # * <tt>:ssl_timeout</tt> -The SSL timeout in seconds.
571
616
  def ssl_options=(options)
572
- @connection = nil
617
+ self._connection = nil
573
618
  @ssl_options = options
574
619
  end
575
620
 
@@ -586,27 +631,28 @@ module ActiveResource
586
631
  # The +refresh+ parameter toggles whether or not the \connection is refreshed at every request
587
632
  # or not (defaults to <tt>false</tt>).
588
633
  def connection(refresh = false)
589
- if defined?(@connection) || superclass == Object
590
- @connection = Connection.new(site, format) if refresh || @connection.nil?
591
- @connection.proxy = proxy if proxy
592
- @connection.user = user if user
593
- @connection.password = password if password
594
- @connection.auth_type = auth_type if auth_type
595
- @connection.timeout = timeout if timeout
596
- @connection.ssl_options = ssl_options if ssl_options
597
- @connection
634
+ if _connection_defined? || superclass == Object
635
+ self._connection = Connection.new(site, format) if refresh || _connection.nil?
636
+ _connection.proxy = proxy if proxy
637
+ _connection.user = user if user
638
+ _connection.password = password if password
639
+ _connection.auth_type = auth_type if auth_type
640
+ _connection.timeout = timeout if timeout
641
+ _connection.open_timeout = open_timeout if open_timeout
642
+ _connection.read_timeout = read_timeout if read_timeout
643
+ _connection.ssl_options = ssl_options if ssl_options
644
+ _connection
598
645
  else
599
646
  superclass.connection
600
647
  end
601
648
  end
602
649
 
603
650
  def headers
604
- @headers ||= {}
605
-
651
+ self._headers ||= {}
606
652
  if superclass != Object && superclass.headers
607
- @headers = superclass.headers.merge(@headers)
653
+ self._headers = superclass.headers.merge(_headers)
608
654
  else
609
- @headers
655
+ _headers
610
656
  end
611
657
  end
612
658
 
@@ -774,7 +820,7 @@ module ActiveResource
774
820
  # Returns the new resource instance.
775
821
  #
776
822
  def build(attributes = {})
777
- attrs = self.format.decode(connection.get("#{new_element_path(attributes)}", headers).body)
823
+ attrs = self.format.decode(connection.get("#{new_element_path(attributes)}", headers).body).merge(attributes)
778
824
  self.new(attrs)
779
825
  end
780
826
 
@@ -871,8 +917,8 @@ module ActiveResource
871
917
 
872
918
  case scope
873
919
  when :all then find_every(options)
874
- when :first then find_every(options).first
875
- when :last then find_every(options).last
920
+ when :first then find_every(options).to_a.first
921
+ when :last then find_every(options).to_a.last
876
922
  when :one then find_one(options)
877
923
  else find_single(scope, options)
878
924
  end
@@ -1560,4 +1606,7 @@ module ActiveResource
1560
1606
  include ActiveModel::Serializers::Xml
1561
1607
  include ActiveResource::Reflection
1562
1608
  end
1609
+
1610
+ ActiveSupport.run_load_hooks(:active_resource, Base)
1563
1611
  end
1612
+
@@ -4,7 +4,7 @@ require 'active_support/inflector'
4
4
  module ActiveResource # :nodoc:
5
5
  class Collection # :nodoc:
6
6
  include Enumerable
7
- delegate :to_xml, :to_yaml, :length, :collect, :map, :each, :all?, :include?, :to_ary, :size, :last, :first, :[], :to => :to_a
7
+ delegate :to_yaml, :all?, *Array.instance_methods(false), :to => :to_a
8
8
 
9
9
  # The array of actual elements returned by index actions
10
10
  attr_accessor :elements, :resource_class, :original_params
@@ -31,7 +31,7 @@ module ActiveResource # :nodoc:
31
31
  #
32
32
  # class Post < ActiveResource::Base
33
33
  # self.site = "http://example.com"
34
- # self.collection_parser = PostParser
34
+ # self.collection_parser = PostCollection
35
35
  # end
36
36
  #
37
37
  # And the collection parser:
@@ -20,7 +20,7 @@ module ActiveResource
20
20
  :head => 'Accept'
21
21
  }
22
22
 
23
- attr_reader :site, :user, :password, :auth_type, :timeout, :proxy, :ssl_options
23
+ attr_reader :site, :user, :password, :auth_type, :timeout, :open_timeout, :read_timeout, :proxy, :ssl_options
24
24
  attr_accessor :format
25
25
 
26
26
  class << self
@@ -33,7 +33,7 @@ module ActiveResource
33
33
  # attribute to the URI for the remote resource service.
34
34
  def initialize(site, format = ActiveResource::Formats::JsonFormat)
35
35
  raise ArgumentError, 'Missing site URI' unless site
36
- @user = @password = nil
36
+ @proxy = @user = @password = nil
37
37
  self.site = site
38
38
  self.format = format
39
39
  end
@@ -71,6 +71,16 @@ module ActiveResource
71
71
  @timeout = timeout
72
72
  end
73
73
 
74
+ # Sets the number of seconds after which HTTP connects to the remote service should time out.
75
+ def open_timeout=(timeout)
76
+ @open_timeout = timeout
77
+ end
78
+
79
+ # Sets the number of seconds after which HTTP read requests to the remote service should time out.
80
+ def read_timeout=(timeout)
81
+ @read_timeout = timeout
82
+ end
83
+
74
84
  # Hash of options applied to Net::HTTP instance when +site+ protocol is 'https'.
75
85
  def ssl_options=(options)
76
86
  @ssl_options = options
@@ -180,6 +190,8 @@ module ActiveResource
180
190
  https.open_timeout = @timeout
181
191
  https.read_timeout = @timeout
182
192
  end
193
+ https.open_timeout = @open_timeout if defined?(@open_timeout)
194
+ https.read_timeout = @read_timeout if defined?(@read_timeout)
183
195
  end
184
196
  end
185
197
 
@@ -260,16 +272,19 @@ module ActiveResource
260
272
  end
261
273
 
262
274
  def auth_attributes_for(uri, request_digest, params)
263
- [
264
- %Q(username="#{@user}"),
265
- %Q(realm="#{params['realm']}"),
266
- %Q(qop="#{params['qop']}"),
267
- %Q(uri="#{uri.path}"),
268
- %Q(nonce="#{params['nonce']}"),
269
- %Q(nc="0"),
270
- %Q(cnonce="#{params['cnonce']}"),
271
- %Q(opaque="#{params['opaque']}"),
272
- %Q(response="#{request_digest}")].join(", ")
275
+ auth_attrs =
276
+ [
277
+ %Q(username="#{@user}"),
278
+ %Q(realm="#{params['realm']}"),
279
+ %Q(qop="#{params['qop']}"),
280
+ %Q(uri="#{uri.path}"),
281
+ %Q(nonce="#{params['nonce']}"),
282
+ %Q(nc="0"),
283
+ %Q(cnonce="#{params['cnonce']}"),
284
+ %Q(response="#{request_digest}")]
285
+
286
+ auth_attrs << %Q(opaque="#{params['opaque']}") unless params['opaque'].blank?
287
+ auth_attrs.join(", ")
273
288
  end
274
289
 
275
290
  def http_format_header(http_method)
@@ -214,6 +214,31 @@ module ActiveResource
214
214
  requests.clear
215
215
  responses.clear
216
216
  end
217
+
218
+ # Enables all ActiveResource::Connection instances to use real
219
+ # Net::HTTP instance instead of a mock.
220
+ def enable_net_connection!
221
+ @@net_connection_enabled = true
222
+ end
223
+
224
+ # Sets all ActiveResource::Connection to use HttpMock instances.
225
+ def disable_net_connection!
226
+ @@net_connection_enabled = false
227
+ end
228
+
229
+ # Checks if real requests can be used instead of the default mock used in tests.
230
+ def net_connection_enabled?
231
+ if defined?(@@net_connection_enabled)
232
+ @@net_connection_enabled
233
+ else
234
+ @@net_connection_enabled = false
235
+ end
236
+ end
237
+
238
+ def net_connection_disabled?
239
+ !net_connection_enabled?
240
+ end
241
+
217
242
  end
218
243
 
219
244
  # body? methods
@@ -325,8 +350,26 @@ module ActiveResource
325
350
  private
326
351
  silence_warnings do
327
352
  def http
328
- @http ||= HttpMock.new(@site)
353
+ if unstub_http?
354
+ @http = configure_http(new_http)
355
+ elsif stub_http?
356
+ @http = http_stub
357
+ end
358
+ @http ||= http_stub
329
359
  end
360
+
361
+ def http_stub
362
+ HttpMock.new(@site)
363
+ end
364
+
365
+ def unstub_http?
366
+ HttpMock.net_connection_enabled? && defined?(@http) && @http.kind_of?(HttpMock)
367
+ end
368
+
369
+ def stub_http?
370
+ HttpMock.net_connection_disabled? && defined?(@http) && @http.kind_of?(Net::HTTP)
371
+ end
372
+
330
373
  end
331
374
  end
332
375
  end
@@ -10,5 +10,16 @@ module ActiveResource
10
10
  ActiveResource::Base.send "#{k}=", v
11
11
  end
12
12
  end
13
+
14
+ config.after_initialize do |app|
15
+ ActiveSupport.on_load(:active_resource) do
16
+ ActiveResource::Base.instantiate_observers
17
+
18
+ ActionDispatch::Reloader.to_prepare do
19
+ ActiveResource::Base.instantiate_observers
20
+ end
21
+ end
22
+ end
13
23
  end
14
- end
24
+ end
25
+
@@ -71,7 +71,7 @@ module ActiveResource
71
71
 
72
72
  path = singleton_path(prefix_options, query_options)
73
73
  resp = self.format.decode(self.connection.get(path, self.headers).body)
74
- instantiate_record(resp, {})
74
+ instantiate_record(resp, prefix_options)
75
75
  end
76
76
 
77
77
  end
@@ -0,0 +1,61 @@
1
+ module ThreadsafeAttributes
2
+ def self.included(klass)
3
+ klass.extend(ClassMethods)
4
+ end
5
+
6
+ module ClassMethods
7
+ def threadsafe_attribute(*attrs)
8
+ attrs.each do |attr|
9
+ define_method attr do
10
+ get_threadsafe_attribute(attr)
11
+ end
12
+
13
+ define_method "#{attr}=" do |value|
14
+ set_threadsafe_attribute(attr, value)
15
+ end
16
+
17
+ define_method "#{attr}_defined?" do
18
+ threadsafe_attribute_defined?(attr)
19
+ end
20
+ end
21
+ end
22
+ end
23
+
24
+ private
25
+
26
+ def get_threadsafe_attribute(name)
27
+ if threadsafe_attribute_defined_by_thread?(name, Thread.current)
28
+ get_threadsafe_attribute_by_thread(name, Thread.current)
29
+ elsif threadsafe_attribute_defined_by_thread?(name, Thread.main)
30
+ value = get_threadsafe_attribute_by_thread(name, Thread.main)
31
+ value = value.dup if value
32
+ set_threadsafe_attribute_by_thread(name, value, Thread.current)
33
+ value
34
+ end
35
+ end
36
+
37
+ def set_threadsafe_attribute(name, value)
38
+ set_threadsafe_attribute_by_thread(name, value, Thread.current)
39
+ unless threadsafe_attribute_defined_by_thread?(name, Thread.main)
40
+ set_threadsafe_attribute_by_thread(name, value, Thread.main)
41
+ end
42
+ end
43
+
44
+ def threadsafe_attribute_defined?(name)
45
+ threadsafe_attribute_defined_by_thread?(name, Thread.current) || ((Thread.current != Thread.main) && threadsafe_attribute_defined_by_thread?(name, Thread.main))
46
+ end
47
+
48
+ def get_threadsafe_attribute_by_thread(name, thread)
49
+ thread["active.resource.#{name}.#{self.object_id}"]
50
+ end
51
+
52
+ def set_threadsafe_attribute_by_thread(name, value, thread)
53
+ thread["active.resource.#{name}.#{self.object_id}.defined"] = true
54
+ thread["active.resource.#{name}.#{self.object_id}"] = value
55
+ end
56
+
57
+ def threadsafe_attribute_defined_by_thread?(name, thread)
58
+ thread["active.resource.#{name}.#{self.object_id}.defined"]
59
+ end
60
+
61
+ end
@@ -13,7 +13,7 @@ module ActiveResource
13
13
  # or not (by passing true).
14
14
  def from_array(messages, save_cache = false)
15
15
  clear unless save_cache
16
- humanized_attributes = Hash[@base.attributes.keys.map { |attr_name| [attr_name.humanize, attr_name] }]
16
+ humanized_attributes = Hash[@base.known_attributes.map { |attr_name| [attr_name.humanize, attr_name] }]
17
17
  messages.each do |message|
18
18
  attr_message = humanized_attributes.keys.sort_by { |a| -a.length }.detect do |attr_name|
19
19
  if message[0, attr_name.size + 1] == "#{attr_name} "
@@ -35,7 +35,7 @@ module ActiveResource
35
35
 
36
36
  messages.each do |(key,errors)|
37
37
  errors.each do |error|
38
- if @base.attributes.keys.include?(key)
38
+ if @base.known_attributes.include?(key)
39
39
  add key, error
40
40
  elsif key == 'base'
41
41
  self[:base] << error
@@ -1,7 +1,7 @@
1
1
  module ActiveResource
2
2
  module VERSION #:nodoc:
3
3
  MAJOR = 4
4
- MINOR = 0
4
+ MINOR = 1
5
5
  TINY = 0
6
6
  PRE = nil
7
7
 
@@ -0,0 +1 @@
1
+ require 'active_resource'
metadata CHANGED
@@ -1,83 +1,83 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activeresource
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.0.0
4
+ version: 4.1.0
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: 2013-06-26 00:00:00.000000000 Z
11
+ date: 2016-06-10 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
19
  version: '4.0'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - ~>
24
+ - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: '4.0'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: activemodel
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - ~>
31
+ - - "~>"
32
32
  - !ruby/object:Gem::Version
33
33
  version: '4.0'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - ~>
38
+ - - "~>"
39
39
  - !ruby/object:Gem::Version
40
40
  version: '4.0'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: rails-observers
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - ~>
45
+ - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: 0.1.1
47
+ version: 0.1.2
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - ~>
52
+ - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: 0.1.1
54
+ version: 0.1.2
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: rake
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - '>='
59
+ - - ">="
60
60
  - !ruby/object:Gem::Version
61
61
  version: '0'
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - '>='
66
+ - - ">="
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0'
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: mocha
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
- - - '>='
73
+ - - ">="
74
74
  - !ruby/object:Gem::Version
75
75
  version: 0.13.0
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
- - - '>='
80
+ - - ">="
81
81
  - !ruby/object:Gem::Version
82
82
  version: 0.13.0
83
83
  description: REST on Rails. Wrap your RESTful web app with Ruby classes and work with
@@ -89,20 +89,21 @@ extra_rdoc_files:
89
89
  - README.rdoc
90
90
  files:
91
91
  - README.rdoc
92
+ - lib/active_resource.rb
93
+ - lib/active_resource/associations.rb
92
94
  - lib/active_resource/associations/builder/association.rb
93
95
  - lib/active_resource/associations/builder/belongs_to.rb
94
96
  - lib/active_resource/associations/builder/has_many.rb
95
97
  - lib/active_resource/associations/builder/has_one.rb
96
- - lib/active_resource/associations.rb
97
98
  - lib/active_resource/base.rb
98
99
  - lib/active_resource/callbacks.rb
99
100
  - lib/active_resource/collection.rb
100
101
  - lib/active_resource/connection.rb
101
102
  - lib/active_resource/custom_methods.rb
102
103
  - lib/active_resource/exceptions.rb
104
+ - lib/active_resource/formats.rb
103
105
  - lib/active_resource/formats/json_format.rb
104
106
  - lib/active_resource/formats/xml_format.rb
105
- - lib/active_resource/formats.rb
106
107
  - lib/active_resource/http_mock.rb
107
108
  - lib/active_resource/log_subscriber.rb
108
109
  - lib/active_resource/observing.rb
@@ -110,32 +111,33 @@ files:
110
111
  - lib/active_resource/reflection.rb
111
112
  - lib/active_resource/schema.rb
112
113
  - lib/active_resource/singleton.rb
114
+ - lib/active_resource/threadsafe_attributes.rb
113
115
  - lib/active_resource/validations.rb
114
116
  - lib/active_resource/version.rb
115
- - lib/active_resource.rb
117
+ - lib/activeresource.rb
116
118
  homepage: http://www.rubyonrails.org
117
119
  licenses:
118
120
  - MIT
119
121
  metadata: {}
120
122
  post_install_message:
121
123
  rdoc_options:
122
- - --main
124
+ - "--main"
123
125
  - README.rdoc
124
126
  require_paths:
125
127
  - lib
126
128
  required_ruby_version: !ruby/object:Gem::Requirement
127
129
  requirements:
128
- - - '>='
130
+ - - ">="
129
131
  - !ruby/object:Gem::Version
130
132
  version: 1.9.3
131
133
  required_rubygems_version: !ruby/object:Gem::Requirement
132
134
  requirements:
133
- - - '>='
135
+ - - ">="
134
136
  - !ruby/object:Gem::Version
135
137
  version: '0'
136
138
  requirements: []
137
139
  rubyforge_project:
138
- rubygems_version: 2.0.3
140
+ rubygems_version: 2.5.1
139
141
  signing_key:
140
142
  specification_version: 4
141
143
  summary: REST modeling framework (part of Rails).