motion-resource 0.1.3 → 0.1.4
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +35 -0
- data/Rakefile +1 -1
- data/lib/motion-resource/associations.rb +11 -6
- data/lib/motion-resource/base.rb +10 -1
- data/lib/motion-resource/crud.rb +27 -8
- data/lib/motion-resource/find.rb +11 -9
- data/lib/motion-resource/requests.rb +25 -16
- data/lib/motion-resource/url_encoder.rb +45 -0
- data/lib/motion-resource/urls.rb +9 -5
- data/lib/motion-resource/version.rb +1 -1
- data/spec/env.rb +8 -3
- data/spec/motion-resource/associations/belongs_to_spec.rb +34 -0
- data/spec/motion-resource/base_spec.rb +10 -0
- data/spec/motion-resource/crud_spec.rb +42 -0
- data/spec/motion-resource/find_spec.rb +14 -0
- data/spec/motion-resource/requests_spec.rb +2 -1
- data/spec/motion-resource/{string_spec.rb → url_encoder_spec.rb} +14 -10
- metadata +7 -7
- data/lib/motion-resource/string.rb +0 -46
data/README.md
CHANGED
@@ -2,6 +2,8 @@
|
|
2
2
|
|
3
3
|
This is a library for using JSON APIs in RubyMotion apps. It is based on [RemoteModel](https://github.com/clayallsopp/remote_model), however it is an almost complete rewrite. Also, it is inspired by ActiveResource.
|
4
4
|
|
5
|
+
This gem needs RubyMotion version 2.3 or higher.
|
6
|
+
|
5
7
|
## Installation
|
6
8
|
|
7
9
|
Add MotionResource to your Gemfile, like this:
|
@@ -43,6 +45,38 @@ Now, we can access a user's posts like that:
|
|
43
45
|
|
44
46
|
Note that the blocks are called asynchronously.
|
45
47
|
|
48
|
+
## URL encoding
|
49
|
+
|
50
|
+
A different url encoding implementation can be substituted by setting MotionResource::Base.url_encoder.
|
51
|
+
For instance to include the fixed parameter 'foo' on every request:
|
52
|
+
|
53
|
+
class CustomEncoder < MotionResource::UrlEncoder
|
54
|
+
def build_query_string(url, params = {})
|
55
|
+
params[:foo] => 42
|
56
|
+
super(url,params)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
MotionResource::Base.url_encoder = CustomEncoder.new
|
60
|
+
|
61
|
+
## Error Handling
|
62
|
+
|
63
|
+
Pass a second block parameter to capture error information:
|
64
|
+
|
65
|
+
User.find_all do |users, response|
|
66
|
+
if response.ok?
|
67
|
+
puts users.inspect
|
68
|
+
else
|
69
|
+
App.alert response.error_message
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
`response` will be an instance of [BubbleWrap::HTTP::Response](http://rdoc.info/github/rubymotion/BubbleWrap/master/file/README.md#HTTP)
|
74
|
+
|
75
|
+
## Reachability
|
76
|
+
|
77
|
+
It's important to check the reachability status of a host before making a request, or you may get intermitent connectivity errors.
|
78
|
+
For an example of how to do so, see `when_reachable` in [TinyMon](https://github.com/tkadauke/TinyMon).
|
79
|
+
|
46
80
|
## Setup
|
47
81
|
|
48
82
|
You can configure every model separately; however you will most likely want to configure things like the root_url the same for every model:
|
@@ -54,3 +88,4 @@ Don't forget the trailing '/' here!
|
|
54
88
|
# Forking
|
55
89
|
|
56
90
|
Feel free to fork and submit pull requests!
|
91
|
+
|
data/Rakefile
CHANGED
@@ -28,7 +28,7 @@ module MotionResource
|
|
28
28
|
|
29
29
|
define_method name do |&block|
|
30
30
|
if block.nil?
|
31
|
-
instance_variable_get("@#{name}") || []
|
31
|
+
instance_variable_get("@#{name}") || instance_variable_set("@#{name}", [])
|
32
32
|
else
|
33
33
|
if cached = instance_variable_get("@#{name}")
|
34
34
|
cached_response = instance_variable_get("@#{name}_response")
|
@@ -67,7 +67,12 @@ module MotionResource
|
|
67
67
|
end
|
68
68
|
end
|
69
69
|
|
70
|
-
def belongs_to(name,
|
70
|
+
def belongs_to(name, options = {})
|
71
|
+
default_options = {
|
72
|
+
:params => lambda { |o| Hash.new },
|
73
|
+
:class_name => name.to_s.classify
|
74
|
+
}
|
75
|
+
options = default_options.merge(options)
|
71
76
|
define_method name do |&block|
|
72
77
|
if block.nil?
|
73
78
|
instance_variable_get("@#{name}")
|
@@ -77,8 +82,8 @@ module MotionResource
|
|
77
82
|
MotionResource::Base.request_block_call(block, cached, cached_response)
|
78
83
|
return
|
79
84
|
end
|
80
|
-
|
81
|
-
|
85
|
+
klass = Object.const_get(options[:class_name])
|
86
|
+
klass.find(self.send("#{name}_id"), options[:params].call(self)) do |result, response|
|
82
87
|
instance_variable_set("@#{name}", result)
|
83
88
|
instance_variable_set("@#{name}_response", response)
|
84
89
|
MotionResource::Base.request_block_call(block, result, response)
|
@@ -87,8 +92,8 @@ module MotionResource
|
|
87
92
|
end
|
88
93
|
|
89
94
|
define_method "#{name}=" do |value|
|
90
|
-
|
91
|
-
value
|
95
|
+
value = Object.const_get(options[:class_name]).instantiate(value) if value.is_a?(Hash)
|
96
|
+
instance_variable_set("@#{name}_id", value.id) if value.respond_to?(:id)
|
92
97
|
instance_variable_set("@#{name}", value)
|
93
98
|
end
|
94
99
|
|
data/lib/motion-resource/base.rb
CHANGED
@@ -18,7 +18,12 @@ module MotionResource
|
|
18
18
|
|
19
19
|
class << self
|
20
20
|
def instantiate(json)
|
21
|
-
|
21
|
+
if json.is_a?(Hash)
|
22
|
+
json = json.symbolize_keys
|
23
|
+
else
|
24
|
+
json = { primary_key => json.to_i }
|
25
|
+
end
|
26
|
+
|
22
27
|
raise ArgumentError, "No :#{primary_key} parameter given for #{self.name}.instantiate" unless json[primary_key]
|
23
28
|
|
24
29
|
klass = if json[:type]
|
@@ -41,6 +46,10 @@ module MotionResource
|
|
41
46
|
result
|
42
47
|
end
|
43
48
|
|
49
|
+
def json_root
|
50
|
+
self.name.underscore.pluralize
|
51
|
+
end
|
52
|
+
|
44
53
|
def identity_map
|
45
54
|
@identity_map ||= {}
|
46
55
|
end
|
data/lib/motion-resource/crud.rb
CHANGED
@@ -1,24 +1,22 @@
|
|
1
1
|
module MotionResource
|
2
2
|
class Base
|
3
|
-
def save(&block)
|
3
|
+
def save(options = {}, &block)
|
4
4
|
run_callbacks :save do
|
5
|
-
@new_record ? create(&block) : update(&block)
|
5
|
+
@new_record ? create(options, &block) : update(options, &block)
|
6
6
|
end
|
7
7
|
end
|
8
8
|
|
9
|
-
def update(&block)
|
9
|
+
def update(options = {}, &block)
|
10
10
|
run_callbacks :update do
|
11
|
-
self.class.put(member_url, :payload =>
|
11
|
+
self.class.put(member_url, :payload => build_payload(options)) do |response, json|
|
12
12
|
self.class.request_block_call(block, json.blank? ? self : self.class.instantiate(json), response) if block
|
13
13
|
end
|
14
14
|
end
|
15
15
|
end
|
16
16
|
|
17
|
-
def create(&block)
|
18
|
-
# weird heisenbug: Specs crash without that line :(
|
19
|
-
dummy = self
|
17
|
+
def create(options = {}, &block)
|
20
18
|
run_callbacks :create do
|
21
|
-
self.class.post(collection_url, :payload =>
|
19
|
+
self.class.post(collection_url, :payload => build_payload(options)) do |response, json|
|
22
20
|
self.class.request_block_call(block, json.blank? ? self : self.class.instantiate(json), response) if block
|
23
21
|
end
|
24
22
|
end
|
@@ -43,5 +41,26 @@ module MotionResource
|
|
43
41
|
self.class.request_block_call(block, json.blank? ? nil : self.class.instantiate(json), response) if block
|
44
42
|
end
|
45
43
|
end
|
44
|
+
|
45
|
+
protected
|
46
|
+
def build_payload(options)
|
47
|
+
includes = Array(options[:include]).inject({}) do |hash, var|
|
48
|
+
if var.to_s =~ /^(.*?)_attributes$/
|
49
|
+
association_name = $1
|
50
|
+
else
|
51
|
+
association_name = var.to_s
|
52
|
+
end
|
53
|
+
|
54
|
+
if respond_to?(association_name)
|
55
|
+
hash[var.to_s] = send(association_name).map(&:attributes)
|
56
|
+
else
|
57
|
+
raise ArgumentError, "No association #{var} found"
|
58
|
+
end
|
59
|
+
|
60
|
+
hash
|
61
|
+
end
|
62
|
+
|
63
|
+
{ self.class.name.underscore => attributes.merge(includes) }
|
64
|
+
end
|
46
65
|
end
|
47
66
|
end
|
data/lib/motion-resource/find.rb
CHANGED
@@ -2,11 +2,11 @@ module MotionResource
|
|
2
2
|
class Base
|
3
3
|
class << self
|
4
4
|
def find(id, params = {}, &block)
|
5
|
-
fetch_member(
|
5
|
+
fetch_member(self.url_encoder.fill_url_params(member_url_or_default, params.merge(id: id)), &block)
|
6
6
|
end
|
7
7
|
|
8
8
|
def find_all(params = {}, &block)
|
9
|
-
fetch_collection(
|
9
|
+
fetch_collection(self.url_encoder.fill_url_params(collection_url_or_default, params), &block)
|
10
10
|
end
|
11
11
|
|
12
12
|
def fetch_member(url, &block)
|
@@ -28,9 +28,9 @@ module MotionResource
|
|
28
28
|
if json.class == Array
|
29
29
|
arr_rep = json
|
30
30
|
elsif json.class == Hash
|
31
|
-
|
32
|
-
if json.has_key?(
|
33
|
-
arr_rep = json[
|
31
|
+
root = self.json_root
|
32
|
+
if json.has_key?(root) || json.has_key?(root.to_sym)
|
33
|
+
arr_rep = json[root] || json[root.to_sym]
|
34
34
|
end
|
35
35
|
else
|
36
36
|
# the returned data was something else
|
@@ -38,9 +38,11 @@ module MotionResource
|
|
38
38
|
request_block_call(block, nil, response)
|
39
39
|
return
|
40
40
|
end
|
41
|
-
arr_rep
|
42
|
-
|
43
|
-
|
41
|
+
if arr_rep
|
42
|
+
arr_rep.each { |one_obj_hash|
|
43
|
+
objs << instantiate(one_obj_hash)
|
44
|
+
}
|
45
|
+
end
|
44
46
|
request_block_call(block, objs, response)
|
45
47
|
else
|
46
48
|
request_block_call(block, nil, response)
|
@@ -63,4 +65,4 @@ module MotionResource
|
|
63
65
|
end
|
64
66
|
end
|
65
67
|
end
|
66
|
-
end
|
68
|
+
end
|
@@ -29,7 +29,27 @@ module MotionResource
|
|
29
29
|
@on_auth_failure = block
|
30
30
|
end
|
31
31
|
|
32
|
-
|
32
|
+
protected
|
33
|
+
|
34
|
+
def decode_response(response, url, options)
|
35
|
+
if response.ok?
|
36
|
+
body = response.body.to_str.strip rescue nil
|
37
|
+
logger.log "response: #{body}"
|
38
|
+
if body.blank?
|
39
|
+
return {}
|
40
|
+
else
|
41
|
+
return BubbleWrap::JSON.parse(body)
|
42
|
+
end
|
43
|
+
else
|
44
|
+
if response.status_code.to_s =~ /401/ && @on_auth_failure
|
45
|
+
@on_auth_failure.call
|
46
|
+
end
|
47
|
+
return nil
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
33
53
|
def complete_url(fragment)
|
34
54
|
if fragment[0..3] == "http"
|
35
55
|
return fragment
|
@@ -43,30 +63,19 @@ module MotionResource
|
|
43
63
|
options = call_options
|
44
64
|
options.merge!(MotionResource::Base.default_url_options || {})
|
45
65
|
if query = options.delete(:query)
|
46
|
-
url.build_query_string
|
66
|
+
url = self.url_encoder.build_query_string(url, query)
|
47
67
|
end
|
48
68
|
if self.default_url_options
|
49
69
|
options.merge!(self.default_url_options)
|
50
70
|
end
|
51
71
|
|
52
|
-
url.insert_extension
|
72
|
+
url = self.url_encoder.insert_extension(url, self.extension)
|
53
73
|
|
54
74
|
logger.log "#{method.upcase} #{url}"
|
75
|
+
logger.log "payload: #{options[:payload]}" if options[:payload]
|
55
76
|
|
56
77
|
BubbleWrap::HTTP.send(method, url, options) do |response|
|
57
|
-
|
58
|
-
body = response.body.to_str.strip rescue nil
|
59
|
-
logger.log "response: #{body}"
|
60
|
-
if body.blank?
|
61
|
-
block.call(response, {})
|
62
|
-
else
|
63
|
-
block.call response, BubbleWrap::JSON.parse(body)
|
64
|
-
end
|
65
|
-
elsif response.status_code.to_s =~ /401/ && @on_auth_failure
|
66
|
-
@on_auth_failure.call
|
67
|
-
else
|
68
|
-
block.call response, nil
|
69
|
-
end
|
78
|
+
block.call response, decode_response(response, url, options)
|
70
79
|
end
|
71
80
|
end
|
72
81
|
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module MotionResource
|
2
|
+
class UrlEncoder
|
3
|
+
def fill_url_params(url, params = {}, delegate = nil)
|
4
|
+
params ||= {}
|
5
|
+
url = url.split('/').collect { |path|
|
6
|
+
ret = path
|
7
|
+
if path[0] == ':'
|
8
|
+
path_sym = path[1..-1].to_sym
|
9
|
+
|
10
|
+
curr = nil
|
11
|
+
if delegate && delegate.respond_to?(path_sym)
|
12
|
+
curr = delegate.send(path_sym)
|
13
|
+
end
|
14
|
+
|
15
|
+
ret = (curr || params.delete(path_sym) || path).to_s
|
16
|
+
end
|
17
|
+
|
18
|
+
ret
|
19
|
+
}.join '/'
|
20
|
+
self.build_query_string(url, params)
|
21
|
+
end
|
22
|
+
|
23
|
+
def build_query_string(url, params = {})
|
24
|
+
return url if params.keys.empty?
|
25
|
+
# fake a url so we avoid regex nastiness with URL's
|
26
|
+
url = NSURL.URLWithString("http://blah.com/#{url}")
|
27
|
+
# build our query string (needs encoding support!)
|
28
|
+
query_string = params.to_query
|
29
|
+
if url.query.nil? || url.query.empty?
|
30
|
+
# strip the beginning / and add the query
|
31
|
+
"#{url.path[1..-1]}?#{query_string}"
|
32
|
+
else
|
33
|
+
"#{url.path[1..-1]}?#{url.query}&#{query_string}"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def insert_extension(url,extension)
|
38
|
+
return url if extension.blank?
|
39
|
+
|
40
|
+
url = NSURL.URLWithString(url)
|
41
|
+
extension = extension.gsub(".", "")
|
42
|
+
url.URLByAppendingPathExtension(extension).absoluteString
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
data/lib/motion-resource/urls.rb
CHANGED
@@ -3,13 +3,16 @@ module MotionResource
|
|
3
3
|
class_attribute :collection_url, :member_url
|
4
4
|
class_attribute :root_url, :default_url_options
|
5
5
|
class_attribute :extension
|
6
|
+
class_attribute :url_encoder
|
7
|
+
|
6
8
|
self.extension = '.json'
|
7
|
-
|
9
|
+
self.url_encoder = UrlEncoder.new
|
10
|
+
|
8
11
|
class << self
|
9
12
|
def custom_urls(params = {})
|
10
13
|
params.each do |name, url_format|
|
11
|
-
define_method name do |
|
12
|
-
|
14
|
+
define_method name do |method_params = {}|
|
15
|
+
self.url_encoder.fill_url_params(url_format, method_params, self)
|
13
16
|
end
|
14
17
|
define_singleton_method name do
|
15
18
|
url_format
|
@@ -24,14 +27,15 @@ module MotionResource
|
|
24
27
|
def member_url_or_default
|
25
28
|
member_url || "#{name.underscore.pluralize}/:#{primary_key}"
|
26
29
|
end
|
30
|
+
|
27
31
|
end
|
28
32
|
|
29
33
|
def collection_url(params = {})
|
30
|
-
self.class.
|
34
|
+
self.class.url_encoder.fill_url_params(self.class.collection_url_or_default, params, self)
|
31
35
|
end
|
32
36
|
|
33
37
|
def member_url(params = {})
|
34
|
-
self.class.
|
38
|
+
self.class.url_encoder.fill_url_params(self.class.member_url_or_default, params, self)
|
35
39
|
end
|
36
40
|
end
|
37
41
|
end
|
data/spec/env.rb
CHANGED
@@ -10,18 +10,23 @@ class Post < MotionResource::Base
|
|
10
10
|
end
|
11
11
|
|
12
12
|
class Comment < MotionResource::Base
|
13
|
-
attr_accessor :post_id, :text
|
13
|
+
attr_accessor :post_id, :account_id, :text
|
14
14
|
|
15
15
|
self.member_url = 'comments/:id'
|
16
16
|
self.collection_url = 'comments'
|
17
17
|
|
18
18
|
belongs_to :post
|
19
|
-
|
19
|
+
belongs_to :account, :class_name => 'User'
|
20
20
|
scope :recent, :url => 'comments/recent'
|
21
|
-
|
22
21
|
custom_urls :by_user_url => 'comments/by_user/:name'
|
23
22
|
end
|
24
23
|
|
24
|
+
class CustomRootComment < Comment
|
25
|
+
def self.json_root
|
26
|
+
'custom'
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
25
30
|
class User < MotionResource::Base
|
26
31
|
self.member_url = 'users/:id'
|
27
32
|
|
@@ -91,6 +91,21 @@ describe "belongs_to" do
|
|
91
91
|
@response.should.be.ok
|
92
92
|
end
|
93
93
|
end
|
94
|
+
|
95
|
+
it "should return correct type of object" do
|
96
|
+
stub_request(:get, "http://example.com/users/1.json").to_return(json: { id: 1, text: 'Hello' })
|
97
|
+
@comment = Comment.new(:account_id => 1)
|
98
|
+
@comment.account do |results, response|
|
99
|
+
@account = results
|
100
|
+
@response = response
|
101
|
+
resume
|
102
|
+
end
|
103
|
+
wait_max 1.0 do
|
104
|
+
@response.should.be.ok
|
105
|
+
@account.class.should == User
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
94
109
|
end
|
95
110
|
|
96
111
|
describe "writer" do
|
@@ -99,11 +114,18 @@ describe "belongs_to" do
|
|
99
114
|
comment.post = { :id => 1, :text => 'Hello' }
|
100
115
|
comment.post.should.is_a Post
|
101
116
|
end
|
117
|
+
|
118
|
+
it "should convert hash to proper type" do
|
119
|
+
comment = Comment.new
|
120
|
+
comment.account = { :id => 1, :text => 'Hello' }
|
121
|
+
comment.account.class.should == User
|
122
|
+
end
|
102
123
|
|
103
124
|
it "should set attributes when assigned with hash" do
|
104
125
|
comment = Comment.new
|
105
126
|
comment.post = { :id => 1, :text => 'Hello' }
|
106
127
|
comment.post.text.should == 'Hello'
|
128
|
+
comment.post.class.should == Post
|
107
129
|
end
|
108
130
|
|
109
131
|
it "should use identity map when assigned with hash" do
|
@@ -119,6 +141,18 @@ describe "belongs_to" do
|
|
119
141
|
comment.post = post
|
120
142
|
comment.post.should == post
|
121
143
|
end
|
144
|
+
|
145
|
+
it "should set association id when assigned with hash" do
|
146
|
+
comment = Comment.new
|
147
|
+
comment.post = { :id => 10 }
|
148
|
+
comment.post_id.should == 10
|
149
|
+
end
|
150
|
+
|
151
|
+
it "should set association id when assigned with object" do
|
152
|
+
comment = Comment.new
|
153
|
+
comment.post = Post.new(:id => 10)
|
154
|
+
comment.post_id.should == 10
|
155
|
+
end
|
122
156
|
end
|
123
157
|
|
124
158
|
describe "piggybacking" do
|
@@ -65,5 +65,15 @@ describe "base" do
|
|
65
65
|
shape1.should.be.identical_to shape2
|
66
66
|
shape1.contents.should == 'something'
|
67
67
|
end
|
68
|
+
|
69
|
+
it "should instantiate with ID number" do
|
70
|
+
shape = Shape.instantiate(3)
|
71
|
+
shape.id.should == 3
|
72
|
+
end
|
73
|
+
|
74
|
+
it "should instantiate with ID string" do
|
75
|
+
shape = Shape.instantiate("5")
|
76
|
+
shape.id.should == 5
|
77
|
+
end
|
68
78
|
end
|
69
79
|
end
|
@@ -65,6 +65,35 @@ describe "crud" do
|
|
65
65
|
@response.should.not.be.ok
|
66
66
|
end
|
67
67
|
end
|
68
|
+
|
69
|
+
it "should include association" do
|
70
|
+
stub_request(:post, "http://example.com/posts.json").to_return(body: "")
|
71
|
+
Post.new.create(:include => :comments) do |result, response|
|
72
|
+
@response = response
|
73
|
+
resume
|
74
|
+
end
|
75
|
+
|
76
|
+
wait_max 1.0 do
|
77
|
+
@response.should.be.ok
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
it "should include association with _attributes suffix" do
|
82
|
+
stub_request(:post, "http://example.com/posts.json").to_return(body: "")
|
83
|
+
Post.new.create(:include => :comments_attributes) do |result, response|
|
84
|
+
@response = response
|
85
|
+
resume
|
86
|
+
end
|
87
|
+
|
88
|
+
wait_max 1.0 do
|
89
|
+
@response.should.be.ok
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
it "should raise error when included association is not found" do
|
94
|
+
stub_request(:post, "http://example.com/posts.json").to_return(body: "")
|
95
|
+
lambda { Post.new.create(:include => :foobar) { |result, response| } }.should.raise(ArgumentError)
|
96
|
+
end
|
68
97
|
end
|
69
98
|
|
70
99
|
describe "update" do
|
@@ -131,6 +160,19 @@ describe "crud" do
|
|
131
160
|
@response.should.not.be.ok
|
132
161
|
end
|
133
162
|
end
|
163
|
+
|
164
|
+
|
165
|
+
it "should include association" do
|
166
|
+
stub_request(:put, "http://example.com/posts/10.json").to_return(body: "")
|
167
|
+
Post.instantiate(:id => 10).update(:include => :comments) do |result, response|
|
168
|
+
@response = response
|
169
|
+
resume
|
170
|
+
end
|
171
|
+
|
172
|
+
wait_max 1.0 do
|
173
|
+
@response.should.be.ok
|
174
|
+
end
|
175
|
+
end
|
134
176
|
end
|
135
177
|
|
136
178
|
describe "destroy" do
|
@@ -76,6 +76,20 @@ describe "find" do
|
|
76
76
|
end
|
77
77
|
end
|
78
78
|
|
79
|
+
it "should allow hash JSON response with custom JSON root" do
|
80
|
+
stub_request(:get, "http://example.com/bar.json").to_return(json: { custom: [{ id: 10, text: '42' }] })
|
81
|
+
CustomRootComment.fetch_collection("bar") do |result|
|
82
|
+
@result = result
|
83
|
+
resume
|
84
|
+
end
|
85
|
+
|
86
|
+
wait_max 1.0 do
|
87
|
+
@result.should.is_a Array
|
88
|
+
@result.first.should.is_a CustomRootComment
|
89
|
+
@result.first.text.should == '42'
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
79
93
|
it "should give nil object if fetching collection fails" do
|
80
94
|
stub_request(:get, "http://example.com/bar.json").to_return(status_code: 404)
|
81
95
|
Comment.fetch_collection("bar") do |result|
|
@@ -120,7 +120,8 @@ describe "requests" do
|
|
120
120
|
it "should call a block given to on_auth_failure on 401" do
|
121
121
|
stub_request(:get, "http://example.com/comments/10.json").to_return(status_code: 401)
|
122
122
|
@fail = false
|
123
|
-
Comment.on_auth_failure { @fail = true
|
123
|
+
Comment.on_auth_failure { @fail = true }
|
124
|
+
|
124
125
|
Comment.new.get("comments/10") do |response, json|
|
125
126
|
resume
|
126
127
|
end
|
@@ -2,34 +2,38 @@ class DelegateObject
|
|
2
2
|
attr_accessor :id, :name
|
3
3
|
end
|
4
4
|
|
5
|
-
describe "
|
5
|
+
describe "url encoder" do
|
6
|
+
before do
|
7
|
+
@encoder = MotionResource::Base.url_encoder
|
8
|
+
end
|
9
|
+
|
6
10
|
it "should fill url params from params hash" do
|
7
|
-
string = "accounts/:id/users/:name"
|
11
|
+
string = @encoder.fill_url_params("accounts/:id/users/:name", {id: 10, name: 'john'})
|
8
12
|
string.should == "accounts/10/users/john"
|
9
13
|
end
|
10
14
|
|
11
15
|
it "should insert an extension if missing" do
|
12
|
-
string = "accounts/fabulous"
|
16
|
+
string = @encoder.insert_extension("accounts/fabulous",".json")
|
13
17
|
string.should == "accounts/fabulous.json"
|
14
18
|
end
|
15
19
|
|
16
20
|
it "should not insert extension if it is blank" do
|
17
|
-
string = "accounts/fabulous"
|
21
|
+
string = @encoder.insert_extension("accounts/fabulous","")
|
18
22
|
string.should == "accounts/fabulous"
|
19
23
|
end
|
20
24
|
|
21
25
|
it "should add a query string for non-url params" do
|
22
|
-
string = "accounts/fabulous"
|
26
|
+
string = @encoder.build_query_string("accounts/fabulous", {foo: 10, moo: "rar"})
|
23
27
|
string.should == "accounts/fabulous?foo=10&moo=rar"
|
24
28
|
end
|
25
29
|
|
26
30
|
it "should not add a ? when building a query string if it exists" do
|
27
|
-
string = "accounts/fabulous?"
|
31
|
+
string = @encoder.build_query_string("accounts/fabulous?", {foo: 10, moo: "rar"})
|
28
32
|
string.should == "accounts/fabulous?foo=10&moo=rar"
|
29
33
|
end
|
30
34
|
|
31
35
|
it "should tag new query params onto existing ones" do
|
32
|
-
string = "accounts/fabulous?moo=rar"
|
36
|
+
string = @encoder.build_query_string("accounts/fabulous?moo=rar", {foo: 10})
|
33
37
|
string.should == "accounts/fabulous?moo=rar&foo=10"
|
34
38
|
end
|
35
39
|
|
@@ -37,15 +41,15 @@ describe "String" do
|
|
37
41
|
obj = DelegateObject.new
|
38
42
|
obj.id = 10
|
39
43
|
obj.name = 'john'
|
40
|
-
string = "accounts/:id/users/:name"
|
44
|
+
string = @encoder.fill_url_params("accounts/:id/users/:name", {}, obj)
|
41
45
|
string.should == "accounts/10/users/john"
|
42
46
|
end
|
43
47
|
|
44
48
|
it "should not crash when a param is unknown" do
|
45
|
-
lambda { "accounts/:id"
|
49
|
+
lambda { @encoder.fill_url_params("accounts/:id", {}) }.should.not.raise
|
46
50
|
end
|
47
51
|
|
48
52
|
it "should not crash when params hash contains an unused value" do
|
49
|
-
lambda { "accounts"
|
53
|
+
lambda { @encoder.fill_url_params("accounts", {foo:'bar'}) }.should.not.raise
|
50
54
|
end
|
51
55
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: motion-resource
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.4
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-
|
12
|
+
date: 2013-07-16 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: bubble-wrap
|
@@ -90,7 +90,7 @@ files:
|
|
90
90
|
- lib/motion-resource/logger.rb
|
91
91
|
- lib/motion-resource/requests.rb
|
92
92
|
- lib/motion-resource/spec_helpers.rb
|
93
|
-
- lib/motion-resource/
|
93
|
+
- lib/motion-resource/url_encoder.rb
|
94
94
|
- lib/motion-resource/urls.rb
|
95
95
|
- lib/motion-resource/version.rb
|
96
96
|
- motion-resource.gemspec
|
@@ -105,7 +105,7 @@ files:
|
|
105
105
|
- spec/motion-resource/crud_spec.rb
|
106
106
|
- spec/motion-resource/find_spec.rb
|
107
107
|
- spec/motion-resource/requests_spec.rb
|
108
|
-
- spec/motion-resource/
|
108
|
+
- spec/motion-resource/url_encoder_spec.rb
|
109
109
|
- spec/motion-resource/urls_spec.rb
|
110
110
|
homepage: https://github.com/tkadauke/motion-resource
|
111
111
|
licenses: []
|
@@ -121,7 +121,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
121
121
|
version: '0'
|
122
122
|
segments:
|
123
123
|
- 0
|
124
|
-
hash:
|
124
|
+
hash: 3639631242463817566
|
125
125
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
126
126
|
none: false
|
127
127
|
requirements:
|
@@ -130,7 +130,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
130
130
|
version: '0'
|
131
131
|
segments:
|
132
132
|
- 0
|
133
|
-
hash:
|
133
|
+
hash: 3639631242463817566
|
134
134
|
requirements: []
|
135
135
|
rubyforge_project:
|
136
136
|
rubygems_version: 1.8.25
|
@@ -149,5 +149,5 @@ test_files:
|
|
149
149
|
- spec/motion-resource/crud_spec.rb
|
150
150
|
- spec/motion-resource/find_spec.rb
|
151
151
|
- spec/motion-resource/requests_spec.rb
|
152
|
-
- spec/motion-resource/
|
152
|
+
- spec/motion-resource/url_encoder_spec.rb
|
153
153
|
- spec/motion-resource/urls_spec.rb
|
@@ -1,46 +0,0 @@
|
|
1
|
-
class String
|
2
|
-
# Takes in a hash and spits out the formatted string
|
3
|
-
# Checks the delegate first
|
4
|
-
def fill_url_params(params = {}, delegate = nil)
|
5
|
-
params ||= {}
|
6
|
-
split = self.split '/'
|
7
|
-
url = split.collect { |path|
|
8
|
-
ret = path
|
9
|
-
if path[0] == ':'
|
10
|
-
path_sym = path[1..-1].to_sym
|
11
|
-
|
12
|
-
curr = nil
|
13
|
-
if delegate && delegate.respond_to?(path_sym)
|
14
|
-
curr = delegate.send(path_sym)
|
15
|
-
end
|
16
|
-
|
17
|
-
ret = (curr || params.delete(path_sym) || path).to_s
|
18
|
-
end
|
19
|
-
|
20
|
-
ret
|
21
|
-
}.join '/'
|
22
|
-
url.build_query_string! params
|
23
|
-
end
|
24
|
-
|
25
|
-
def build_query_string!(params = {})
|
26
|
-
return self if params.keys.empty?
|
27
|
-
# fake a url so we avoid regex nastiness with URL's
|
28
|
-
url = NSURL.URLWithString("http://blah.com/#{self}")
|
29
|
-
# build our query string (needs encoding support!)
|
30
|
-
query_string = params.to_query
|
31
|
-
if url.query.nil? || url.query.empty?
|
32
|
-
# strip the beginning / and add the query
|
33
|
-
self.replace "#{url.path[1..-1]}?#{query_string}"
|
34
|
-
else
|
35
|
-
self.replace "#{url.path[1..-1]}?#{url.query}&#{query_string}"
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
def insert_extension!(extension)
|
40
|
-
return self if extension.blank?
|
41
|
-
|
42
|
-
url = NSURL.URLWithString(self)
|
43
|
-
extension = extension.gsub(".", "")
|
44
|
-
self.replace url.URLByAppendingPathExtension(extension).absoluteString
|
45
|
-
end
|
46
|
-
end
|