remotable 0.3.0 → 0.4.0.beta2

Sign up to get free protection for your applications and to get access to all the features.
@@ -4,20 +4,20 @@ require "active_support/concern"
4
4
 
5
5
  module ActiveResourceFixes
6
6
  extend ActiveSupport::Concern
7
-
8
-
7
+
8
+
9
9
  # ! ActiveModel::AttributeMethods assumes that :attribute is the target
10
10
  # for attribute lookup. ActiveResource doesn't define that method.
11
11
  def attribute(method)
12
12
  attributes[method]
13
13
  end
14
-
15
-
14
+
15
+
16
16
  included do
17
17
  alias_method_chain :destroy, :validation
18
18
  end
19
-
20
-
19
+
20
+
21
21
  # ActiveResource::Validations overrides ActiveResource::Base#save
22
22
  # to rescue from ActiveResource::ResourceInvalid and record the
23
23
  # resource's errors. Do the same for `destroy`.
@@ -31,7 +31,7 @@ module ActiveResourceFixes
31
31
  load_remote_errors(@remote_errors, true)
32
32
  false
33
33
  end
34
-
34
+
35
35
  end
36
36
 
37
37
 
@@ -50,19 +50,19 @@ module ActiveResourceFixes30
50
50
  super(method_symbol, include_private)
51
51
  end
52
52
  end
53
-
53
+
54
54
  # ! in this method, don't check the Content-Type header: rack doesn't always return it
55
55
  def load_attributes_from_response(response)
56
56
  if !response.body.nil? && response.body.strip.size > 0
57
57
  load(self.class.format.decode(response.body))
58
58
  end
59
59
  end
60
-
60
+
61
61
  end
62
62
 
63
63
 
64
64
  module ActiveResourceFixes31
65
-
65
+
66
66
  # ActiveResource hacks method_missing without hacking respond_to?
67
67
  # In fact, it responds to any method that ends in an equals sign.
68
68
  # It also responds to any method that matches an attribute name.
@@ -76,7 +76,7 @@ module ActiveResourceFixes31
76
76
  super(method_symbol, include_private)
77
77
  end
78
78
  end
79
-
79
+
80
80
  # ! in this method, don't check the Content-Type header: rack doesn't always return it
81
81
  def load_attributes_from_response(response)
82
82
  if !response.body.nil? && response.body.strip.size > 0
@@ -84,7 +84,7 @@ module ActiveResourceFixes31
84
84
  @persisted = true
85
85
  end
86
86
  end
87
-
87
+
88
88
  end
89
89
 
90
90
  if Rails.version >= '3.2'
@@ -101,12 +101,12 @@ ActiveResource::Base.send(:include, ActiveResourceFixes)
101
101
 
102
102
 
103
103
  module ActiveResourceJsonFormatFixes
104
-
104
+
105
105
  def decode(json)
106
106
  return {} if json.blank? # <-- insert this line. json will be nil if response is 304
107
107
  super
108
108
  end
109
-
109
+
110
110
  end
111
111
 
112
112
  ActiveResource::Formats::JsonFormat.extend ActiveResourceJsonFormatFixes
@@ -117,7 +117,7 @@ ActiveResource::Formats::JsonFormat.extend ActiveResourceJsonFormatFixes
117
117
  # However, this is not what Rails Responders are inclined to return.
118
118
 
119
119
  class ActiveResource::Errors
120
-
120
+
121
121
  # Grabs errors from an array of messages (like ActiveRecord::Validations).
122
122
  # The second parameter directs the errors cache to be cleared (default)
123
123
  # or not (by passing true).
@@ -130,5 +130,5 @@ class ActiveResource::Errors
130
130
  end
131
131
  end
132
132
  end
133
-
133
+
134
134
  end
@@ -7,51 +7,60 @@ module Remotable
7
7
  module Adapters
8
8
  module ActiveResource
9
9
  extend ActiveSupport::Concern
10
-
11
-
12
-
10
+
11
+
12
+
13
13
  def key?(attribute)
14
14
  attributes.key?(attribute.to_s)
15
15
  end
16
-
16
+
17
17
  def [](attribute)
18
18
  attributes[attribute.to_s]
19
19
  end
20
-
20
+
21
21
  def []=(attribute, value)
22
22
  attributes[attribute.to_s] = value
23
23
  end
24
-
25
-
26
-
24
+
25
+
26
+
27
27
  # If we use `remote_key` to explicitly set the path where
28
28
  # this resource ought to be found, then we should use the
29
29
  # same path when updating or destroying this resource.
30
- #
30
+ #
31
31
  # To accomplish this, we need to override ActiveResource's
32
32
  # element_path to return the canonical path for this resource.
33
-
33
+
34
34
  attr_accessor :remote_key_path
35
-
35
+
36
36
  def element_path(*args)
37
37
  return remote_key_path if remote_key_path
38
38
  super
39
39
  end
40
-
41
-
42
-
40
+
41
+
42
+
43
+ def destroy
44
+ super
45
+ rescue ::ActiveResource::ResourceNotFound
46
+ $!.extend Remotable::NotFound
47
+ raise
48
+ end
49
+
50
+
51
+
43
52
  module ClassMethods
44
-
53
+
45
54
  IF_MODIFIED_SINCE = "If-Modified-Since".freeze
46
-
47
-
48
-
55
+
56
+
57
+
49
58
  def new_resource
50
59
  new
51
60
  end
52
-
53
-
54
-
61
+
62
+
63
+
55
64
  # This is always invoked by instance#fetch_remote_resource.
56
65
  # It expects to find a remote counterpart for a local resource.
57
66
  # It should always return a NullRemote object that doesn't
@@ -59,8 +68,8 @@ module Remotable
59
68
  def find_by_for_local(local_record, path)
60
69
  had_previous_value = headers.key?(IF_MODIFIED_SINCE)
61
70
  previous_value = headers[IF_MODIFIED_SINCE]
62
-
63
- headers[IF_MODIFIED_SINCE] = Remotable.http_format_time(local_record.updated_at) if local_record.accepts_not_modified?
71
+
72
+ headers[IF_MODIFIED_SINCE] = Remotable.http_format_time(local_record.remote_updated_at) if local_record.accepts_not_modified?
64
73
  find_by(path)
65
74
  ensure
66
75
  if had_previous_value
@@ -69,19 +78,22 @@ module Remotable
69
78
  headers.delete(IF_MODIFIED_SINCE)
70
79
  end
71
80
  end
72
-
81
+
73
82
  def find_by(path)
74
83
  find_by!(path)
75
84
  rescue ::ActiveResource::ResourceNotFound
76
85
  nil
77
86
  end
78
-
87
+
79
88
  def find_by!(path)
80
89
  expanded_path = expanded_path_for(path)
81
90
  Remotable.logger.info "[remotable:#{name.underscore}] GET #{expanded_path} (timeout: #{timeout})"
82
91
  find(:one, :from => expanded_path).tap do |resource|
83
92
  resource.remote_key_path = expanded_path if resource
84
93
  end
94
+ rescue SocketError, EOFError
95
+ $!.extend Remotable::NetworkError
96
+ raise
85
97
  rescue ::ActiveResource::TimeoutError
86
98
  $!.extend Remotable::TimeoutError
87
99
  raise
@@ -90,9 +102,9 @@ module Remotable
90
102
  $!.extend Remotable::TimeoutError if $!.response.code == 504
91
103
  raise
92
104
  end
93
-
94
-
95
-
105
+
106
+
107
+
96
108
  def expanded_path_for(path)
97
109
  if relative_path?(path)
98
110
  URI.join_url_segments(prefix, collection_name, "#{path}.#{format.extension}")
@@ -100,15 +112,15 @@ module Remotable
100
112
  path
101
113
  end
102
114
  end
103
-
104
-
105
-
115
+
116
+
117
+
106
118
  private
107
-
119
+
108
120
  def relative_path?(path)
109
121
  !(path.start_with?("/") || path["://"])
110
122
  end
111
-
123
+
112
124
  end
113
125
  end
114
126
  end
@@ -1,7 +1,7 @@
1
1
  module Enumerable
2
-
2
+
3
3
  def map_to_self(result={})
4
4
  inject(result) {|hash, value| hash.merge(value => value)}
5
5
  end
6
-
6
+
7
7
  end
@@ -1,23 +1,23 @@
1
1
  module Remotable
2
2
  module CoreExt
3
3
  module Object
4
-
5
-
4
+
5
+
6
6
  def respond_to_all?(*methods)
7
7
  respond_to = method(:respond_to?)
8
8
  methods.flatten.all?(&respond_to)
9
9
  end
10
-
10
+
11
11
  def responds_to(*methods)
12
12
  respond_to = method(:respond_to?)
13
13
  methods.flatten.select(&respond_to)
14
14
  end
15
-
15
+
16
16
  def does_not_respond_to(*methods)
17
17
  methods.flatten - self.responds_to(methods)
18
18
  end
19
-
20
-
19
+
20
+
21
21
  end
22
22
  end
23
23
  end
@@ -4,16 +4,16 @@ require "uri"
4
4
  module Remotable
5
5
  module CoreExt
6
6
  module URI
7
-
8
-
7
+
8
+
9
9
  def join_url_segments(*segments)
10
10
  segments = segments.dup.flatten.map(&:to_s)
11
11
  first_segment = segments.shift.gsub(/\/$/, "")
12
12
  segments.map! { |seg| seg.gsub(/(^\/)|(\/$)/, "") }
13
13
  [first_segment, *segments].join("/")
14
14
  end
15
-
16
-
15
+
16
+
17
17
  end
18
18
  end
19
19
  end
@@ -2,4 +2,6 @@ module Remotable
2
2
  module Error; end
3
3
  module TimeoutError; include Error; end
4
4
  module ServiceUnavailableError; include Error; end
5
+ module NetworkError; include Error; end
6
+ module NotFound; include Error; end
5
7
  end
@@ -1,37 +1,37 @@
1
1
  module Remotable
2
2
  class LoggerWrapper
3
-
3
+
4
4
  def initialize(logger)
5
5
  @logger = logger
6
6
  end
7
-
7
+
8
8
  attr_reader :logger
9
-
9
+
10
10
  def debug(*args)
11
11
  logger.debug(*args) if log? :debug
12
12
  end
13
-
13
+
14
14
  def info(*args)
15
15
  logger.info(*args) if log? :info
16
16
  end
17
-
17
+
18
18
  def warn(*args)
19
19
  logger.warn(*args) if log? :warn
20
20
  end
21
-
21
+
22
22
  def error(*args)
23
23
  logger.error(*args) if log? :error
24
24
  end
25
-
25
+
26
26
  private
27
-
27
+
28
28
  LEVELS = [:debug, :info, :warn, :error].freeze
29
-
29
+
30
30
  def log?(value)
31
31
  level = LEVELS.index(Remotable.log_level)
32
32
  value = LEVELS.index(value)
33
33
  value >= level
34
34
  end
35
-
35
+
36
36
  end
37
37
  end
@@ -1,11 +1,11 @@
1
1
  module Remotable
2
2
  module Nosync
3
-
4
-
3
+
4
+
5
5
  def nosync!
6
6
  self.nosync = true
7
7
  end
8
-
8
+
9
9
  def nosync(new_value=true)
10
10
  old_value = @nosync
11
11
  self.nosync = new_value
@@ -13,19 +13,19 @@ module Remotable
13
13
  ensure
14
14
  @nosync = old_value
15
15
  end
16
-
16
+
17
17
  def nosync=(val)
18
18
  @nosync = val
19
19
  end
20
-
20
+
21
21
  def nosync_value?
22
22
  !@nosync.nil?
23
23
  end
24
-
24
+
25
25
  def nosync?
26
26
  @nosync == true
27
27
  end
28
-
29
-
28
+
29
+
30
30
  end
31
31
  end
@@ -1,8 +1,8 @@
1
1
  module Remotable
2
2
  class NullRemote
3
-
3
+
4
4
  class << self
5
-
5
+
6
6
  # This is always invoked by instance#fetch_remote_resource.
7
7
  # It expects to find a remote counterpart for a local resource.
8
8
  # It should always return a NullRemote object that doesn't
@@ -10,7 +10,7 @@ module Remotable
10
10
  def find_by_for_local(local_record, remote_key, fetch_value)
11
11
  new
12
12
  end
13
-
13
+
14
14
  # This is always invoked via class#find_remote_resource_by
15
15
  # by class#fetch_by. It gives the remote model an opportunity
16
16
  # to discover a remote object that doesn't have a local
@@ -19,36 +19,36 @@ module Remotable
19
19
  def find_by(remote_attr, value)
20
20
  nil
21
21
  end
22
-
22
+
23
23
  def new_resource
24
24
  new
25
25
  end
26
-
26
+
27
27
  end
28
-
29
-
30
-
28
+
29
+
30
+
31
31
  # NullRemote needs to receive setter messages and
32
32
  # swallow them. It doesn't need to respond to getter
33
33
  # messages since it has nothing to say.
34
34
  def []=(attribute, value)
35
35
  end
36
-
36
+
37
37
  def key?(attribute)
38
38
  false
39
39
  end
40
-
40
+
41
41
  def save
42
42
  true
43
43
  end
44
-
44
+
45
45
  def errors
46
46
  {}
47
47
  end
48
-
48
+
49
49
  def destroy
50
50
  true
51
51
  end
52
-
52
+
53
53
  end
54
54
  end