motion-resource 0.0.2 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -7,3 +7,4 @@ resources/*.storyboardc
7
7
  .bundle
8
8
  Gemfile.lock
9
9
  pkg/*
10
+ .dat*
data/README.md CHANGED
@@ -12,22 +12,22 @@ Add MotionResource to your Gemfile, like this:
12
12
 
13
13
  Consider this example for a fictional blog API.
14
14
 
15
- class User < RemoteModule::RemoteModel
15
+ class User < MotionResource::Base
16
16
  attr_accessor :id
17
17
 
18
18
  has_many :posts
19
19
 
20
- collection_url "users"
21
- member_url "users/:id"
20
+ self.collection_url = "users"
21
+ self.member_url = "users/:id"
22
22
  end
23
23
 
24
- class Post < RemoteModule::RemoteModel
24
+ class Post < MotionResource::Base
25
25
  attr_accessor :id, :user_id, :title, :text
26
26
 
27
27
  belongs_to :user
28
28
 
29
- collection_url "users/:user_id/posts"
30
- member_url "users/:user_id/posts/:id"
29
+ self.collection_url = "users/:user_id/posts"
30
+ self.member_url = "users/:user_id/posts/:id"
31
31
  end
32
32
 
33
33
  Now, we can access a user's posts like that:
data/Rakefile CHANGED
@@ -5,10 +5,10 @@ require "bundler/gem_tasks"
5
5
  Bundler.setup
6
6
  Bundler.require
7
7
 
8
- $:.unshift("./lib/")
9
- require './lib/motion-resource'
8
+ require 'motion-resource'
10
9
 
11
10
  Motion::Project::App.setup do |app|
12
11
  # Use `rake config' to see complete project settings.
13
12
  app.name = 'MotionResource'
14
- end
13
+ app.detect_dependencies = false
14
+ end
@@ -1,10 +1,11 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  $:.unshift("/Library/RubyMotion/lib")
3
3
  require 'motion/project'
4
- require 'motion-support'
5
- require 'motion-resource'
4
+
5
+ require '../../lib/motion-resource'
6
6
 
7
7
  Motion::Project::App.setup do |app|
8
8
  # Use `rake config' to see complete project settings.
9
9
  app.name = 'Colr'
10
+ app.detect_dependencies = false
10
11
  end
@@ -1,6 +1,7 @@
1
1
  module MotionResource
2
2
  class Base
3
- class_inheritable_array :attributes
3
+ class_attribute :attributes
4
+ self.attributes = []
4
5
 
5
6
  class << self
6
7
  def attribute(*fields)
@@ -1,6 +1,6 @@
1
1
  module MotionResource
2
2
  class Base
3
- class_inheritable_accessor :logger
3
+ class_attribute :logger
4
4
  self.logger = MotionSupport::NullLogger.new
5
5
  end
6
6
  end
@@ -7,7 +7,7 @@ module MotionResource
7
7
  self.class.send(method, *args, &block)
8
8
  end
9
9
  end
10
-
10
+
11
11
  class << self
12
12
  def get(url, params = {}, &block)
13
13
  http_call(:get, url, params, &block)
@@ -25,6 +25,10 @@ module MotionResource
25
25
  http_call(:delete, url, params, &block)
26
26
  end
27
27
 
28
+ def on_auth_failure(&block)
29
+ @on_auth_failure = block
30
+ end
31
+
28
32
  private
29
33
  def complete_url(fragment)
30
34
  if fragment[0..3] == "http"
@@ -34,20 +38,21 @@ module MotionResource
34
38
  end
35
39
 
36
40
  def http_call(method, url, call_options = {}, &block)
37
- options = call_options
41
+ url = complete_url(url)
42
+
43
+ options = call_options
38
44
  options.merge!(MotionResource::Base.default_url_options || {})
39
- url += self.extension
40
45
  if query = options.delete(:query)
41
- if url.index("?").nil?
42
- url += "?"
43
- end
44
- url += query.map{|k,v| "#{k}=#{v}"}.join('&')
46
+ url.build_query_string!(query)
45
47
  end
46
48
  if self.default_url_options
47
49
  options.merge!(self.default_url_options)
48
50
  end
49
- logger.log "#{method.upcase} #{complete_url(url)}"
50
- BubbleWrap::HTTP.send(method, complete_url(url), options) do |response|
51
+ logger.log "#{method.upcase} #{url}"
52
+
53
+ url.insert_extension!(self.extension)
54
+
55
+ BubbleWrap::HTTP.send(method, url, options) do |response|
51
56
  if response.ok?
52
57
  body = response.body.to_str.strip rescue nil
53
58
  logger.log "response: #{body}"
@@ -56,6 +61,8 @@ module MotionResource
56
61
  else
57
62
  block.call response, BubbleWrap::JSON.parse(body)
58
63
  end
64
+ elsif response.status_code.to_s =~ /401/ && @on_auth_failure
65
+ @on_auth_failure.call
59
66
  else
60
67
  block.call response, nil
61
68
  end
@@ -4,7 +4,7 @@ class String
4
4
  def fill_url_params(params = {}, delegate = nil)
5
5
  params ||= {}
6
6
  split = self.split '/'
7
- split.collect { |path|
7
+ url = split.collect { |path|
8
8
  ret = path
9
9
  if path[0] == ':'
10
10
  path_sym = path[1..-1].to_sym
@@ -14,10 +14,33 @@ class String
14
14
  curr = delegate.send(path_sym)
15
15
  end
16
16
 
17
- ret = (curr || params[path_sym] || path).to_s
17
+ ret = (curr || params.delete(path_sym) || path).to_s
18
18
  end
19
19
 
20
20
  ret
21
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.map{|k,v| "#{k}=#{v}"}.join('&')
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
22
45
  end
23
46
  end
@@ -1,8 +1,8 @@
1
1
  module MotionResource
2
2
  class Base
3
- class_inheritable_accessor :collection_url, :member_url
4
- class_inheritable_accessor :root_url, :default_url_options
5
- class_inheritable_accessor :extension
3
+ class_attribute :collection_url, :member_url
4
+ class_attribute :root_url, :default_url_options
5
+ class_attribute :extension
6
6
  self.extension = '.json'
7
7
 
8
8
  class << self
@@ -1,3 +1,3 @@
1
1
  module MotionResource
2
- VERSION = "0.0.2"
2
+ VERSION = "0.1.0"
3
3
  end
@@ -1,5 +1,4 @@
1
- require "motion-resource/version"
1
+ require 'motion-support'
2
2
  require 'bubble-wrap'
3
- Dir.glob(File.join(File.dirname(__FILE__), 'motion-resource/*.rb')).each do |file|
4
- BW.require file
5
- end
3
+
4
+ Motion::Require.all(Dir.glob(File.expand_path('../motion-resource/**/*.rb', __FILE__)))
@@ -15,6 +15,6 @@ Gem::Specification.new do |s|
15
15
  s.require_paths = ["lib"]
16
16
 
17
17
  s.add_dependency 'bubble-wrap'
18
- s.add_dependency 'motion-support'
18
+ s.add_dependency 'motion-support', ">= 0.2.0"
19
19
  s.add_development_dependency 'rake'
20
20
  end
@@ -1,6 +1,6 @@
1
1
  describe "requests" do
2
2
  extend WebStub::SpecHelpers
3
-
3
+
4
4
  it "should define GET method on instance and class" do
5
5
  Comment.new.should.respond_to :get
6
6
  Comment.should.respond_to :get
@@ -20,100 +20,113 @@ describe "requests" do
20
20
  Comment.new.should.respond_to :delete
21
21
  Comment.should.respond_to :delete
22
22
  end
23
-
23
+
24
24
  it "should add query string" do
25
25
  stub_request(:get, "http://example.com/comments/10.json?foo=bar").to_return(json: { id: 10 })
26
26
  Comment.new.get("comments/10", :query => { :foo => 'bar' }) do |response, json|
27
27
  @result = json
28
28
  resume
29
29
  end
30
-
30
+
31
31
  wait_max 1.0 do
32
32
  @result.should.not.be.nil
33
33
  end
34
34
  end
35
-
35
+
36
36
  it "should parse JSON in response" do
37
37
  stub_request(:get, "http://example.com/comments/10.json").to_return(json: { id: 10, foo: 'bar' })
38
38
  Comment.new.get("comments/10") do |response, json|
39
39
  @result = json
40
40
  resume
41
41
  end
42
-
42
+
43
43
  wait_max 1.0 do
44
44
  @result.should == { "id" => 10, "foo" => "bar" }
45
45
  end
46
46
  end
47
-
47
+
48
48
  it "should yield empty hash if response is blank" do
49
49
  stub_request(:get, "http://example.com/comments/10.json").to_return(body: "")
50
50
  Comment.new.get("comments/10") do |response, json|
51
51
  @result = json
52
52
  resume
53
53
  end
54
-
54
+
55
55
  wait_max 1.0 do
56
56
  @result.should == {}
57
57
  end
58
58
  end
59
-
59
+
60
60
  it "should yield nil if response is not ok" do
61
61
  stub_request(:get, "http://example.com/comments/10.json").to_return(status_code: 404)
62
62
  Comment.new.get("comments/10") do |response, json|
63
63
  @result = json
64
64
  resume
65
65
  end
66
-
66
+
67
67
  wait_max 1.0 do
68
68
  @result.should.be.nil
69
69
  end
70
70
  end
71
-
71
+
72
72
  it "should get attributes" do
73
73
  stub_request(:get, "http://example.com/comments/10.json").to_return(json: { id: 10, text: "Hello" })
74
74
  Comment.new.get("comments/10") do |response, json|
75
75
  @result = json
76
76
  resume
77
77
  end
78
-
78
+
79
79
  wait_max 1.0 do
80
80
  @result["text"].should == "Hello"
81
81
  end
82
82
  end
83
-
83
+
84
84
  it "should post" do
85
85
  stub_request(:post, "http://example.com/comments.json").to_return(json: { id: 10 })
86
86
  Comment.post("comments") do |response, json|
87
87
  @result = json
88
88
  resume
89
89
  end
90
-
90
+
91
91
  wait_max 1.0 do
92
92
  @result.should.not.be.nil
93
93
  end
94
94
  end
95
-
95
+
96
96
  it "should put" do
97
97
  stub_request(:put, "http://example.com/comments/10.json").to_return(json: { id: 10 })
98
98
  Comment.new.put("comments/10") do |response, json|
99
99
  @result = json
100
100
  resume
101
101
  end
102
-
102
+
103
103
  wait_max 1.0 do
104
104
  @result.should.not.be.nil
105
105
  end
106
106
  end
107
-
107
+
108
108
  it "should delete" do
109
109
  stub_request(:delete, "http://example.com/comments/10.json").to_return(json: { id: 10 })
110
110
  Comment.new.delete("comments/10") do |response, json|
111
111
  @result = json
112
112
  resume
113
113
  end
114
-
114
+
115
115
  wait_max 1.0 do
116
116
  @result.should.not.be.nil
117
117
  end
118
118
  end
119
+
120
+ it "should call a block given to on_auth_failure on 401" do
121
+ stub_request(:get, "http://example.com/comments/10.json").to_return(status_code: 401)
122
+ @fail = false
123
+ Comment.on_auth_failure { @fail = true; resume }
124
+ Comment.new.get("comments/10") do |response, json|
125
+ resume
126
+ end
127
+
128
+ wait_max 1.0 do
129
+ @fail.should == true
130
+ end
131
+ end
119
132
  end
@@ -7,7 +7,32 @@ describe "String" do
7
7
  string = "accounts/:id/users/:name".fill_url_params(id: 10, name: 'john')
8
8
  string.should == "accounts/10/users/john"
9
9
  end
10
-
10
+
11
+ it "should insert an extension if missing" do
12
+ string = "accounts/fabulous".insert_extension!(".json")
13
+ string.should == "accounts/fabulous.json"
14
+ end
15
+
16
+ it "should not insert extension if it is blank" do
17
+ string = "accounts/fabulous".insert_extension!("")
18
+ string.should == "accounts/fabulous"
19
+ end
20
+
21
+ it "should add a query string for non-url params" do
22
+ string = "accounts/fabulous".build_query_string!(foo: 10, moo: "rar")
23
+ string.should == "accounts/fabulous?foo=10&moo=rar"
24
+ end
25
+
26
+ it "should not add a ? when building a query string if it exists" do
27
+ string = "accounts/fabulous?".build_query_string!(foo: 10, moo: "rar")
28
+ string.should == "accounts/fabulous?foo=10&moo=rar"
29
+ end
30
+
31
+ it "should tag new query params onto existing ones" do
32
+ string = "accounts/fabulous?moo=rar".build_query_string!(foo: 10)
33
+ string.should == "accounts/fabulous?moo=rar&foo=10"
34
+ end
35
+
11
36
  it "should fill url params from delegate object" do
12
37
  obj = DelegateObject.new
13
38
  obj.id = 10
@@ -15,11 +40,11 @@ describe "String" do
15
40
  string = "accounts/:id/users/:name".fill_url_params({}, obj)
16
41
  string.should == "accounts/10/users/john"
17
42
  end
18
-
43
+
19
44
  it "should not crash when a param is unknown" do
20
45
  lambda { "accounts/:id".fill_url_params({}) }.should.not.raise
21
46
  end
22
-
47
+
23
48
  it "should not crash when params hash contains an unused value" do
24
49
  lambda { "accounts".fill_url_params(foo: 'bar') }.should.not.raise
25
50
  end
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: motion-resource
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.0.2
5
+ version: 0.1.0
6
6
  platform: ruby
7
7
  authors:
8
8
  - Thomas Kadauke
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2012-12-31 00:00:00 Z
13
+ date: 2013-04-29 00:00:00 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: bubble-wrap
@@ -30,7 +30,7 @@ dependencies:
30
30
  requirements:
31
31
  - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: "0"
33
+ version: 0.2.0
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: *id002
@@ -107,7 +107,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
107
107
  requirements:
108
108
  - - ">="
109
109
  - !ruby/object:Gem::Version
110
- hash: -3639208948173529629
110
+ hash: 1896856864951168664
111
111
  segments:
112
112
  - 0
113
113
  version: "0"
@@ -116,7 +116,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
116
116
  requirements:
117
117
  - - ">="
118
118
  - !ruby/object:Gem::Version
119
- hash: -3639208948173529629
119
+ hash: 1896856864951168664
120
120
  segments:
121
121
  - 0
122
122
  version: "0"