activeresource_csi 2.3.5.p6
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.
- data/CHANGELOG +292 -0
- data/README +165 -0
- data/Rakefile +139 -0
- data/lib/active_resource/base.rb +1157 -0
- data/lib/active_resource/connection.rb +283 -0
- data/lib/active_resource/custom_methods.rb +120 -0
- data/lib/active_resource/exceptions.rb +66 -0
- data/lib/active_resource/formats/json_format.rb +23 -0
- data/lib/active_resource/formats/xml_format.rb +34 -0
- data/lib/active_resource/formats.rb +14 -0
- data/lib/active_resource/http_mock.rb +207 -0
- data/lib/active_resource/validations.rb +290 -0
- data/lib/active_resource/version.rb +9 -0
- data/lib/active_resource.rb +44 -0
- data/lib/activeresource.rb +2 -0
- data/test/abstract_unit.rb +21 -0
- data/test/authorization_test.rb +122 -0
- data/test/base/custom_methods_test.rb +100 -0
- data/test/base/equality_test.rb +52 -0
- data/test/base/load_test.rb +161 -0
- data/test/base_errors_test.rb +85 -0
- data/test/base_test.rb +1038 -0
- data/test/connection_test.rb +238 -0
- data/test/debug.log +5335 -0
- data/test/fixtures/beast.rb +14 -0
- data/test/fixtures/customer.rb +3 -0
- data/test/fixtures/person.rb +3 -0
- data/test/fixtures/proxy.rb +4 -0
- data/test/fixtures/street_address.rb +4 -0
- data/test/format_test.rb +112 -0
- data/test/setter_trap.rb +26 -0
- metadata +119 -0
@@ -0,0 +1,207 @@
|
|
1
|
+
require 'active_resource/connection'
|
2
|
+
|
3
|
+
module ActiveResource
|
4
|
+
class InvalidRequestError < StandardError; end #:nodoc:
|
5
|
+
|
6
|
+
# One thing that has always been a pain with remote web services is testing. The HttpMock
|
7
|
+
# class makes it easy to test your Active Resource models by creating a set of mock responses to specific
|
8
|
+
# requests.
|
9
|
+
#
|
10
|
+
# To test your Active Resource model, you simply call the ActiveResource::HttpMock.respond_to
|
11
|
+
# method with an attached block. The block declares a set of URIs with expected input, and the output
|
12
|
+
# each request should return. The passed in block has any number of entries in the following generalized
|
13
|
+
# format:
|
14
|
+
#
|
15
|
+
# mock.http_method(path, request_headers = {}, body = nil, status = 200, response_headers = {})
|
16
|
+
#
|
17
|
+
# * <tt>http_method</tt> - The HTTP method to listen for. This can be +get+, +post+, +put+, +delete+ or
|
18
|
+
# +head+.
|
19
|
+
# * <tt>path</tt> - A string, starting with a "/", defining the URI that is expected to be
|
20
|
+
# called.
|
21
|
+
# * <tt>request_headers</tt> - Headers that are expected along with the request. This argument uses a
|
22
|
+
# hash format, such as <tt>{ "Content-Type" => "application/xml" }</tt>. This mock will only trigger
|
23
|
+
# if your tests sends a request with identical headers.
|
24
|
+
# * <tt>body</tt> - The data to be returned. This should be a string of Active Resource parseable content,
|
25
|
+
# such as XML.
|
26
|
+
# * <tt>status</tt> - The HTTP response code, as an integer, to return with the response.
|
27
|
+
# * <tt>response_headers</tt> - Headers to be returned with the response. Uses the same hash format as
|
28
|
+
# <tt>request_headers</tt> listed above.
|
29
|
+
#
|
30
|
+
# In order for a mock to deliver its content, the incoming request must match by the <tt>http_method</tt>,
|
31
|
+
# +path+ and <tt>request_headers</tt>. If no match is found an InvalidRequestError exception
|
32
|
+
# will be raised letting you know you need to create a new mock for that request.
|
33
|
+
#
|
34
|
+
# ==== Example
|
35
|
+
# def setup
|
36
|
+
# @matz = { :id => 1, :name => "Matz" }.to_xml(:root => "person")
|
37
|
+
# ActiveResource::HttpMock.respond_to do |mock|
|
38
|
+
# mock.post "/people.xml", {}, @matz, 201, "Location" => "/people/1.xml"
|
39
|
+
# mock.get "/people/1.xml", {}, @matz
|
40
|
+
# mock.put "/people/1.xml", {}, nil, 204
|
41
|
+
# mock.delete "/people/1.xml", {}, nil, 200
|
42
|
+
# end
|
43
|
+
# end
|
44
|
+
#
|
45
|
+
# def test_get_matz
|
46
|
+
# person = Person.find(1)
|
47
|
+
# assert_equal "Matz", person.name
|
48
|
+
# end
|
49
|
+
#
|
50
|
+
class HttpMock
|
51
|
+
class Responder #:nodoc:
|
52
|
+
def initialize(responses)
|
53
|
+
@responses = responses
|
54
|
+
end
|
55
|
+
|
56
|
+
for method in [ :post, :put, :get, :delete, :head ]
|
57
|
+
# def post(path, request_headers = {}, body = nil, status = 200, response_headers = {})
|
58
|
+
# @responses[Request.new(:post, path, nil, request_headers)] = Response.new(body || "", status, response_headers)
|
59
|
+
# end
|
60
|
+
module_eval <<-EOE, __FILE__, __LINE__
|
61
|
+
def #{method}(path, request_headers = {}, body = nil, status = 200, response_headers = {})
|
62
|
+
@responses << [Request.new(:#{method}, path, nil, request_headers), Response.new(body || "", status, response_headers)]
|
63
|
+
end
|
64
|
+
EOE
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
class << self
|
69
|
+
|
70
|
+
# Returns an array of all request objects that have been sent to the mock. You can use this to check
|
71
|
+
# if your model actually sent an HTTP request.
|
72
|
+
#
|
73
|
+
# ==== Example
|
74
|
+
# def setup
|
75
|
+
# @matz = { :id => 1, :name => "Matz" }.to_xml(:root => "person")
|
76
|
+
# ActiveResource::HttpMock.respond_to do |mock|
|
77
|
+
# mock.get "/people/1.xml", {}, @matz
|
78
|
+
# end
|
79
|
+
# end
|
80
|
+
#
|
81
|
+
# def test_should_request_remote_service
|
82
|
+
# person = Person.find(1) # Call the remote service
|
83
|
+
#
|
84
|
+
# # This request object has the same HTTP method and path as declared by the mock
|
85
|
+
# expected_request = ActiveResource::Request.new(:get, "/people/1.xml")
|
86
|
+
#
|
87
|
+
# # Assert that the mock received, and responded to, the expected request from the model
|
88
|
+
# assert ActiveResource::HttpMock.requests.include?(expected_request)
|
89
|
+
# end
|
90
|
+
def requests
|
91
|
+
@@requests ||= []
|
92
|
+
end
|
93
|
+
|
94
|
+
# Returns the list of requests and their mocked responses. Look up a
|
95
|
+
# response for a request using responses.assoc(request).
|
96
|
+
def responses
|
97
|
+
@@responses ||= []
|
98
|
+
end
|
99
|
+
|
100
|
+
# Accepts a block which declares a set of requests and responses for the HttpMock to respond to. See the main
|
101
|
+
# ActiveResource::HttpMock description for a more detailed explanation.
|
102
|
+
def respond_to(pairs = {}) #:yields: mock
|
103
|
+
reset!
|
104
|
+
responses.concat pairs.to_a
|
105
|
+
if block_given?
|
106
|
+
yield Responder.new(responses)
|
107
|
+
else
|
108
|
+
Responder.new(responses)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
# Deletes all logged requests and responses.
|
113
|
+
def reset!
|
114
|
+
requests.clear
|
115
|
+
responses.clear
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
# body? methods
|
120
|
+
{ true => %w(post put),
|
121
|
+
false => %w(get delete head) }.each do |has_body, methods|
|
122
|
+
methods.each do |method|
|
123
|
+
# def post(path, body, headers)
|
124
|
+
# request = ActiveResource::Request.new(:post, path, body, headers)
|
125
|
+
# self.class.requests << request
|
126
|
+
# self.class.responses.assoc(request).try(:second) || raise(InvalidRequestError.new("No response recorded for #{request}"))
|
127
|
+
# end
|
128
|
+
module_eval <<-EOE, __FILE__, __LINE__
|
129
|
+
def #{method}(path, #{'body, ' if has_body}headers)
|
130
|
+
request = ActiveResource::Request.new(:#{method}, path, #{has_body ? 'body, ' : 'nil, '}headers)
|
131
|
+
self.class.requests << request
|
132
|
+
self.class.responses.assoc(request).try(:second) || raise(InvalidRequestError.new("No response recorded for \#{request}"))
|
133
|
+
end
|
134
|
+
EOE
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
def initialize(site) #:nodoc:
|
139
|
+
@site = site
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
class Request
|
144
|
+
attr_accessor :path, :method, :body, :headers
|
145
|
+
|
146
|
+
def initialize(method, path, body = nil, headers = {})
|
147
|
+
@method, @path, @body, @headers = method, path, body, headers.merge(ActiveResource::Connection::HTTP_FORMAT_HEADER_NAMES[method] => 'application/xml')
|
148
|
+
end
|
149
|
+
|
150
|
+
def ==(req)
|
151
|
+
path == req.path && method == req.method && headers == req.headers
|
152
|
+
end
|
153
|
+
|
154
|
+
def to_s
|
155
|
+
"<#{method.to_s.upcase}: #{path} [#{headers}] (#{body})>"
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
class Response
|
160
|
+
attr_accessor :body, :message, :code, :headers
|
161
|
+
|
162
|
+
def initialize(body, message = 200, headers = {})
|
163
|
+
@body, @message, @headers = body, message.to_s, headers
|
164
|
+
@code = @message[0,3].to_i
|
165
|
+
|
166
|
+
resp_cls = Net::HTTPResponse::CODE_TO_OBJ[@code.to_s]
|
167
|
+
if resp_cls && !resp_cls.body_permitted?
|
168
|
+
@body = nil
|
169
|
+
end
|
170
|
+
|
171
|
+
if @body.nil?
|
172
|
+
self['Content-Length'] = "0"
|
173
|
+
else
|
174
|
+
self['Content-Length'] = body.size.to_s
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
def success?
|
179
|
+
(200..299).include?(code)
|
180
|
+
end
|
181
|
+
|
182
|
+
def [](key)
|
183
|
+
headers[key]
|
184
|
+
end
|
185
|
+
|
186
|
+
def []=(key, value)
|
187
|
+
headers[key] = value
|
188
|
+
end
|
189
|
+
|
190
|
+
def ==(other)
|
191
|
+
if (other.is_a?(Response))
|
192
|
+
other.body == body && other.message == message && other.headers == headers
|
193
|
+
else
|
194
|
+
false
|
195
|
+
end
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
class Connection
|
200
|
+
private
|
201
|
+
silence_warnings do
|
202
|
+
def http
|
203
|
+
@http ||= HttpMock.new(@site)
|
204
|
+
end
|
205
|
+
end
|
206
|
+
end
|
207
|
+
end
|
@@ -0,0 +1,290 @@
|
|
1
|
+
module ActiveResource
|
2
|
+
class ResourceInvalid < ClientError #:nodoc:
|
3
|
+
end
|
4
|
+
|
5
|
+
# Active Resource validation is reported to and from this object, which is used by Base#save
|
6
|
+
# to determine whether the object in a valid state to be saved. See usage example in Validations.
|
7
|
+
class Errors
|
8
|
+
include Enumerable
|
9
|
+
attr_reader :errors
|
10
|
+
|
11
|
+
delegate :empty?, :to => :errors
|
12
|
+
|
13
|
+
def initialize(base) # :nodoc:
|
14
|
+
@base, @errors = base, {}
|
15
|
+
end
|
16
|
+
|
17
|
+
# Add an error to the base Active Resource object rather than an attribute.
|
18
|
+
#
|
19
|
+
# ==== Examples
|
20
|
+
# my_folder = Folder.find(1)
|
21
|
+
# my_folder.errors.add_to_base("You can't edit an existing folder")
|
22
|
+
# my_folder.errors.on_base
|
23
|
+
# # => "You can't edit an existing folder"
|
24
|
+
#
|
25
|
+
# my_folder.errors.add_to_base("This folder has been tagged as frozen")
|
26
|
+
# my_folder.valid?
|
27
|
+
# # => false
|
28
|
+
# my_folder.errors.on_base
|
29
|
+
# # => ["You can't edit an existing folder", "This folder has been tagged as frozen"]
|
30
|
+
#
|
31
|
+
def add_to_base(msg)
|
32
|
+
add(:base, msg)
|
33
|
+
end
|
34
|
+
|
35
|
+
# Adds an error to an Active Resource object's attribute (named for the +attribute+ parameter)
|
36
|
+
# with the error message in +msg+.
|
37
|
+
#
|
38
|
+
# ==== Examples
|
39
|
+
# my_resource = Node.find(1)
|
40
|
+
# my_resource.errors.add('name', 'can not be "base"') if my_resource.name == 'base'
|
41
|
+
# my_resource.errors.on('name')
|
42
|
+
# # => 'can not be "base"!'
|
43
|
+
#
|
44
|
+
# my_resource.errors.add('desc', 'can not be blank') if my_resource.desc == ''
|
45
|
+
# my_resource.valid?
|
46
|
+
# # => false
|
47
|
+
# my_resource.errors.on('desc')
|
48
|
+
# # => 'can not be blank!'
|
49
|
+
#
|
50
|
+
def add(attribute, msg)
|
51
|
+
@errors[attribute.to_s] = [] if @errors[attribute.to_s].nil?
|
52
|
+
@errors[attribute.to_s] << msg
|
53
|
+
end
|
54
|
+
|
55
|
+
# Returns true if the specified +attribute+ has errors associated with it.
|
56
|
+
#
|
57
|
+
# ==== Examples
|
58
|
+
# my_resource = Disk.find(1)
|
59
|
+
# my_resource.errors.add('location', 'must be Main') unless my_resource.location == 'Main'
|
60
|
+
# my_resource.errors.on('location')
|
61
|
+
# # => 'must be Main!'
|
62
|
+
#
|
63
|
+
# my_resource.errors.invalid?('location')
|
64
|
+
# # => true
|
65
|
+
# my_resource.errors.invalid?('name')
|
66
|
+
# # => false
|
67
|
+
def invalid?(attribute)
|
68
|
+
!@errors[attribute.to_s].nil?
|
69
|
+
end
|
70
|
+
|
71
|
+
# A method to return the errors associated with +attribute+, which returns nil, if no errors are
|
72
|
+
# associated with the specified +attribute+, the error message if one error is associated with the specified +attribute+,
|
73
|
+
# or an array of error messages if more than one error is associated with the specified +attribute+.
|
74
|
+
#
|
75
|
+
# ==== Examples
|
76
|
+
# my_person = Person.new(params[:person])
|
77
|
+
# my_person.errors.on('login')
|
78
|
+
# # => nil
|
79
|
+
#
|
80
|
+
# my_person.errors.add('login', 'can not be empty') if my_person.login == ''
|
81
|
+
# my_person.errors.on('login')
|
82
|
+
# # => 'can not be empty'
|
83
|
+
#
|
84
|
+
# my_person.errors.add('login', 'can not be longer than 10 characters') if my_person.login.length > 10
|
85
|
+
# my_person.errors.on('login')
|
86
|
+
# # => ['can not be empty', 'can not be longer than 10 characters']
|
87
|
+
def on(attribute)
|
88
|
+
errors = @errors[attribute.to_s]
|
89
|
+
return nil if errors.nil?
|
90
|
+
errors.size == 1 ? errors.first : errors
|
91
|
+
end
|
92
|
+
|
93
|
+
alias :[] :on
|
94
|
+
|
95
|
+
# A method to return errors assigned to +base+ object through add_to_base, which returns nil, if no errors are
|
96
|
+
# associated with the specified +attribute+, the error message if one error is associated with the specified +attribute+,
|
97
|
+
# or an array of error messages if more than one error is associated with the specified +attribute+.
|
98
|
+
#
|
99
|
+
# ==== Examples
|
100
|
+
# my_account = Account.find(1)
|
101
|
+
# my_account.errors.on_base
|
102
|
+
# # => nil
|
103
|
+
#
|
104
|
+
# my_account.errors.add_to_base("This account is frozen")
|
105
|
+
# my_account.errors.on_base
|
106
|
+
# # => "This account is frozen"
|
107
|
+
#
|
108
|
+
# my_account.errors.add_to_base("This account has been closed")
|
109
|
+
# my_account.errors.on_base
|
110
|
+
# # => ["This account is frozen", "This account has been closed"]
|
111
|
+
#
|
112
|
+
def on_base
|
113
|
+
on(:base)
|
114
|
+
end
|
115
|
+
|
116
|
+
# Yields each attribute and associated message per error added.
|
117
|
+
#
|
118
|
+
# ==== Examples
|
119
|
+
# my_person = Person.new(params[:person])
|
120
|
+
#
|
121
|
+
# my_person.errors.add('login', 'can not be empty') if my_person.login == ''
|
122
|
+
# my_person.errors.add('password', 'can not be empty') if my_person.password == ''
|
123
|
+
# messages = ''
|
124
|
+
# my_person.errors.each {|attr, msg| messages += attr.humanize + " " + msg + "<br />"}
|
125
|
+
# messages
|
126
|
+
# # => "Login can not be empty<br />Password can not be empty<br />"
|
127
|
+
#
|
128
|
+
def each
|
129
|
+
@errors.each_key { |attr| @errors[attr].each { |msg| yield attr, msg } }
|
130
|
+
end
|
131
|
+
|
132
|
+
# Yields each full error message added. So Person.errors.add("first_name", "can't be empty") will be returned
|
133
|
+
# through iteration as "First name can't be empty".
|
134
|
+
#
|
135
|
+
# ==== Examples
|
136
|
+
# my_person = Person.new(params[:person])
|
137
|
+
#
|
138
|
+
# my_person.errors.add('login', 'can not be empty') if my_person.login == ''
|
139
|
+
# my_person.errors.add('password', 'can not be empty') if my_person.password == ''
|
140
|
+
# messages = ''
|
141
|
+
# my_person.errors.each_full {|msg| messages += msg + "<br/>"}
|
142
|
+
# messages
|
143
|
+
# # => "Login can not be empty<br />Password can not be empty<br />"
|
144
|
+
#
|
145
|
+
def each_full
|
146
|
+
full_messages.each { |msg| yield msg }
|
147
|
+
end
|
148
|
+
|
149
|
+
# Returns all the full error messages in an array.
|
150
|
+
#
|
151
|
+
# ==== Examples
|
152
|
+
# my_person = Person.new(params[:person])
|
153
|
+
#
|
154
|
+
# my_person.errors.add('login', 'can not be empty') if my_person.login == ''
|
155
|
+
# my_person.errors.add('password', 'can not be empty') if my_person.password == ''
|
156
|
+
# messages = ''
|
157
|
+
# my_person.errors.full_messages.each {|msg| messages += msg + "<br/>"}
|
158
|
+
# messages
|
159
|
+
# # => "Login can not be empty<br />Password can not be empty<br />"
|
160
|
+
#
|
161
|
+
def full_messages
|
162
|
+
full_messages = []
|
163
|
+
|
164
|
+
@errors.each_key do |attr|
|
165
|
+
@errors[attr].each do |msg|
|
166
|
+
next if msg.nil?
|
167
|
+
|
168
|
+
if attr == "base"
|
169
|
+
full_messages << msg
|
170
|
+
else
|
171
|
+
full_messages << [attr.humanize, msg].join(' ')
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
175
|
+
full_messages
|
176
|
+
end
|
177
|
+
|
178
|
+
def clear
|
179
|
+
@errors = {}
|
180
|
+
end
|
181
|
+
|
182
|
+
# Returns the total number of errors added. Two errors added to the same attribute will be counted as such
|
183
|
+
# with this as well.
|
184
|
+
#
|
185
|
+
# ==== Examples
|
186
|
+
# my_person = Person.new(params[:person])
|
187
|
+
# my_person.errors.size
|
188
|
+
# # => 0
|
189
|
+
#
|
190
|
+
# my_person.errors.add('login', 'can not be empty') if my_person.login == ''
|
191
|
+
# my_person.errors.add('password', 'can not be empty') if my_person.password == ''
|
192
|
+
# my_person.error.size
|
193
|
+
# # => 2
|
194
|
+
#
|
195
|
+
def size
|
196
|
+
@errors.values.inject(0) { |error_count, attribute| error_count + attribute.size }
|
197
|
+
end
|
198
|
+
|
199
|
+
alias_method :count, :size
|
200
|
+
alias_method :length, :size
|
201
|
+
|
202
|
+
# Grabs errors from an array of messages (like ActiveRecord::Validations)
|
203
|
+
def from_array(messages)
|
204
|
+
clear
|
205
|
+
humanized_attributes = @base.attributes.keys.inject({}) { |h, attr_name| h.update(attr_name.humanize => attr_name) }
|
206
|
+
messages.each do |message|
|
207
|
+
attr_message = humanized_attributes.keys.detect do |attr_name|
|
208
|
+
if message[0, attr_name.size + 1] == "#{attr_name} "
|
209
|
+
add humanized_attributes[attr_name], message[(attr_name.size + 1)..-1]
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
add_to_base message if attr_message.nil?
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
# Grabs errors from the json response.
|
218
|
+
def from_json(json)
|
219
|
+
array = ActiveSupport::JSON.decode(json)['errors'] rescue []
|
220
|
+
from_array array
|
221
|
+
end
|
222
|
+
|
223
|
+
# Grabs errors from the XML response.
|
224
|
+
def from_xml(xml)
|
225
|
+
array = Array.wrap(Hash.from_xml(xml)['errors']['error']) rescue []
|
226
|
+
from_array array
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
# Module to support validation and errors with Active Resource objects. The module overrides
|
231
|
+
# Base#save to rescue ActiveResource::ResourceInvalid exceptions and parse the errors returned
|
232
|
+
# in the web service response. The module also adds an +errors+ collection that mimics the interface
|
233
|
+
# of the errors provided by ActiveRecord::Errors.
|
234
|
+
#
|
235
|
+
# ==== Example
|
236
|
+
#
|
237
|
+
# Consider a Person resource on the server requiring both a +first_name+ and a +last_name+ with a
|
238
|
+
# <tt>validates_presence_of :first_name, :last_name</tt> declaration in the model:
|
239
|
+
#
|
240
|
+
# person = Person.new(:first_name => "Jim", :last_name => "")
|
241
|
+
# person.save # => false (server returns an HTTP 422 status code and errors)
|
242
|
+
# person.valid? # => false
|
243
|
+
# person.errors.empty? # => false
|
244
|
+
# person.errors.count # => 1
|
245
|
+
# person.errors.full_messages # => ["Last name can't be empty"]
|
246
|
+
# person.errors.on(:last_name) # => "can't be empty"
|
247
|
+
# person.last_name = "Halpert"
|
248
|
+
# person.save # => true (and person is now saved to the remote service)
|
249
|
+
#
|
250
|
+
module Validations
|
251
|
+
def self.included(base) # :nodoc:
|
252
|
+
base.class_eval do
|
253
|
+
alias_method_chain :save, :validation
|
254
|
+
end
|
255
|
+
end
|
256
|
+
|
257
|
+
# Validate a resource and save (POST) it to the remote web service.
|
258
|
+
def save_with_validation
|
259
|
+
save_without_validation
|
260
|
+
true
|
261
|
+
rescue ResourceInvalid => error
|
262
|
+
case error.response['Content-Type']
|
263
|
+
when /xml/
|
264
|
+
errors.from_xml(error.response.body)
|
265
|
+
when /json/
|
266
|
+
errors.from_json(error.response.body)
|
267
|
+
end
|
268
|
+
false
|
269
|
+
end
|
270
|
+
|
271
|
+
# Checks for errors on an object (i.e., is resource.errors empty?).
|
272
|
+
#
|
273
|
+
# ==== Examples
|
274
|
+
# my_person = Person.create(params[:person])
|
275
|
+
# my_person.valid?
|
276
|
+
# # => true
|
277
|
+
#
|
278
|
+
# my_person.errors.add('login', 'can not be empty') if my_person.login == ''
|
279
|
+
# my_person.valid?
|
280
|
+
# # => false
|
281
|
+
def valid?
|
282
|
+
errors.empty?
|
283
|
+
end
|
284
|
+
|
285
|
+
# Returns the Errors object that holds all information about attribute error messages.
|
286
|
+
def errors
|
287
|
+
@errors ||= Errors.new(self)
|
288
|
+
end
|
289
|
+
end
|
290
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2006 David Heinemeier Hansson
|
3
|
+
#
|
4
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
5
|
+
# a copy of this software and associated documentation files (the
|
6
|
+
# "Software"), to deal in the Software without restriction, including
|
7
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
8
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
9
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
10
|
+
# the following conditions:
|
11
|
+
#
|
12
|
+
# The above copyright notice and this permission notice shall be
|
13
|
+
# included in all copies or substantial portions of the Software.
|
14
|
+
#
|
15
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
16
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
17
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
18
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
19
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
20
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
21
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
22
|
+
#++
|
23
|
+
|
24
|
+
begin
|
25
|
+
require 'active_support'
|
26
|
+
rescue LoadError
|
27
|
+
activesupport_path = "#{File.dirname(__FILE__)}/../../activesupport/lib"
|
28
|
+
if File.directory?(activesupport_path)
|
29
|
+
$:.unshift activesupport_path
|
30
|
+
require 'active_support'
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
require 'active_resource/formats'
|
35
|
+
require 'active_resource/base'
|
36
|
+
require 'active_resource/validations'
|
37
|
+
require 'active_resource/custom_methods'
|
38
|
+
|
39
|
+
module ActiveResource
|
40
|
+
Base.class_eval do
|
41
|
+
include Validations
|
42
|
+
include CustomMethods
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'test/unit'
|
3
|
+
require 'active_support/test_case'
|
4
|
+
|
5
|
+
$:.unshift "#{File.dirname(__FILE__)}/../lib"
|
6
|
+
$:.unshift "#{File.dirname(__FILE__)}/../../activesupport/lib"
|
7
|
+
require 'active_resource'
|
8
|
+
require 'active_resource/http_mock'
|
9
|
+
|
10
|
+
$:.unshift "#{File.dirname(__FILE__)}/../test"
|
11
|
+
require 'setter_trap'
|
12
|
+
|
13
|
+
ActiveResource::Base.logger = Logger.new("#{File.dirname(__FILE__)}/debug.log")
|
14
|
+
|
15
|
+
def uses_gem(gem_name, test_name, version = '> 0')
|
16
|
+
gem gem_name.to_s, version
|
17
|
+
require gem_name.to_s
|
18
|
+
yield
|
19
|
+
rescue LoadError
|
20
|
+
$stderr.puts "Skipping #{test_name} tests. `gem install #{gem_name}` and try again."
|
21
|
+
end
|