restfully 0.5.10 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG CHANGED
@@ -1,3 +1,8 @@
1
+ 0.6.0
2
+ * Fixed collection traversal.
3
+ * Query parameters that are Arrays are no longer joined.
4
+ * Added 'next' as valid link relationship.
5
+
1
6
  0.5.10
2
7
  * Direct lookup to the resource if it cannot be found in the collection (for APIs that do not return all the items in a collection) (priteau)
3
8
  * Automatically load next pages of a collection when iterating through it
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.5.10
1
+ 0.6.0
data/lib/restfully.rb CHANGED
@@ -1,10 +1,10 @@
1
1
  require 'backports'
2
2
  require 'yaml'
3
+ require 'restfully/extensions'
3
4
  require 'restfully/error'
4
5
  require 'restfully/parsing'
5
6
  require 'restfully/http'
6
7
  require 'restfully/http/adapters/rest_client_adapter'
7
- require 'restfully/extensions'
8
8
  require 'restfully/session'
9
9
  require 'restfully/special_hash'
10
10
  require 'restfully/special_array'
@@ -12,9 +12,8 @@ require 'restfully/link'
12
12
  require 'restfully/resource'
13
13
  require 'restfully/collection'
14
14
 
15
-
16
15
  module Restfully
17
- VERSION = "0.5.10"
16
+ VERSION = "0.6.0"
18
17
  class << self
19
18
  attr_accessor :adapter
20
19
  end
@@ -28,9 +28,12 @@ module Restfully
28
28
  def each(*args, &block)
29
29
  @items.each_index{ |i|
30
30
  block.call(@items[i])
31
- if i == @items.length-1 && @items.length < self["total"]
31
+ if i == @items.length-1 && @items.length+self["offset"] < self["total"]
32
32
  # load next page
33
- next_page = Collection.new(uri, session).load(:query => {:offset => self["offset"]+@items.length}) rescue nil
33
+ query_options = executed_requests['GET']['options'][:query] || {}
34
+ query_options[:offset] = self["offset"]+@items.length
35
+ query_options[:limit] ||= 200
36
+ next_page = Collection.new(uri, session).load(:query => query_options) rescue nil
34
37
  if next_page && next_page['offset'] != self["offset"]
35
38
  @items.push(*next_page.to_a)
36
39
  end
@@ -2,23 +2,33 @@ class BasicObject #:nodoc:
2
2
  instance_methods.each { |m| undef_method m unless m =~ /^__|instance_eval/ }
3
3
  end unless defined?(BasicObject)
4
4
 
5
- # monkey patching:
6
- class Hash
7
- # This is by no means the standard way to transform ruby objects into query parameters
8
- # but it is targeted at our own needs
5
+ class Object
6
+ # Taken from ActiveSupport
7
+ def to_query(key)
8
+ require 'cgi' unless defined?(CGI) && defined?(CGI::escape)
9
+ "#{CGI.escape(key.to_s)}=#{CGI.escape(to_params.to_s)}"
10
+ end
11
+
9
12
  def to_params
10
- params = ''
11
-
12
- each do |k, v|
13
- if v.is_a?(Array)
14
- params << "#{k}=#{v.join(",")}&"
15
- else
16
- params << "#{k}=#{v.to_s}&"
17
- end
18
- end
13
+ to_s
14
+ end
15
+ end
19
16
 
20
- params.chop!
21
- params
17
+ class Hash
18
+ # Converts a hash into a string suitable for use as a URL query string.
19
+ # An optional <tt>namespace</tt> can be passed to enclose the param names.
20
+ # Taken from ActiveSupport
21
+ def to_params(namespace = nil)
22
+ collect do |key, value|
23
+ value.to_query(namespace ? "#{namespace}[#{key}]" : key)
24
+ end * '&'
22
25
  end
26
+ end
23
27
 
28
+ class Array
29
+ # Taken from ActiveSupport
30
+ def to_query(key)
31
+ prefix = "#{key}[]"
32
+ collect { |value| value.to_query(prefix) }.join '&'
33
+ end
24
34
  end
@@ -1,10 +1,12 @@
1
1
  require 'uri'
2
2
  module Restfully
3
3
  module HTTP
4
+
4
5
  class Request
5
6
  include Headers, Restfully::Parsing
6
7
  attr_reader :headers, :uri
7
8
  attr_accessor :retries
9
+
8
10
  def initialize(url, options = {})
9
11
  options = options.symbolize_keys
10
12
  @uri = url.kind_of?(URI) ? url : URI.parse(url)
@@ -16,7 +18,6 @@ module Restfully
16
18
  @retries = 0
17
19
  end
18
20
 
19
-
20
21
  def body
21
22
  if @body.kind_of?(String)
22
23
  @unserialized_body ||= unserialize(@body, :content_type => @headers['Content-Type'])
@@ -2,7 +2,7 @@ require 'uri'
2
2
  module Restfully
3
3
  class Link
4
4
 
5
- VALID_RELATIONSHIPS = %w{member parent collection self alternate}
5
+ VALID_RELATIONSHIPS = %w{member parent collection self alternate next}
6
6
  RELATIONSHIPS_REQUIRING_TITLE = %w{collection member}
7
7
 
8
8
  attr_reader :rel, :title, :href, :errors
data/restfully.gemspec CHANGED
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{restfully}
8
- s.version = "0.5.10"
8
+ s.version = "0.6.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Cyril Rohr"]
12
- s.date = %q{2010-04-20}
12
+ s.date = %q{2011-01-18}
13
13
  s.default_executable = %q{restfully}
14
14
  s.description = %q{Experimental code for auto-generation of wrappers on top of RESTful APIs that follow HATEOAS principles and provide OPTIONS methods and/or Allow headers.}
15
15
  s.email = %q{cyril.rohr@gmail.com}
@@ -67,7 +67,7 @@ Gem::Specification.new do |s|
67
67
  s.homepage = %q{http://github.com/crohr/restfully}
68
68
  s.rdoc_options = ["--charset=UTF-8"]
69
69
  s.require_paths = ["lib"]
70
- s.rubygems_version = %q{1.3.5}
70
+ s.rubygems_version = %q{1.3.6}
71
71
  s.summary = %q{Experimental code for auto-generation of wrappers on top of RESTful APIs that follow some specific conventions.}
72
72
  s.test_files = [
73
73
  "spec/collection_spec.rb",
@@ -48,8 +48,8 @@ describe Collection do
48
48
  body2["offset"] = 16
49
49
  body2["items"][1]["uid"] = "18th item"
50
50
  collection = Collection.new(@uri, session = mock('session')).load(:body => body)
51
- session.should_receive(:get).with(@uri, :query => {:offset => 8}).ordered.and_return(response = mock("response", :body => body1, :status => 200, :headers => {}))
52
- session.should_receive(:get).with(@uri, :query => {:offset => 16}).ordered.and_return(response = mock("response", :body => body2, :status => 200, :headers => {}))
51
+ session.should_receive(:get).with(@uri, :query => {:offset => 8, :limit => 200}).ordered.and_return(response = mock("response", :body => body1, :status => 200, :headers => {}))
52
+ session.should_receive(:get).with(@uri, :query => {:offset => 16, :limit => 200}).ordered.and_return(response = mock("response", :body => body2, :status => 200, :headers => {}))
53
53
  collection.find{|item| item["uid"] == "18th item"}.should_not be_nil
54
54
  end
55
55
  it "should always return nil if the searched item is not in the collection" do
@@ -9,8 +9,8 @@ describe Restfully::HTTP::Request do
9
9
  :body => {"key" => "value"}.to_json
10
10
  )
11
11
  request.uri.should be_a URI
12
- request.uri.to_s.should == 'https://api.grid5000.fr/sid/grid5000?q1=v1&q2=v2&custom_param1=3,4,5,6&custom_param2=value_custom_param2'
13
- request.uri.query.should == "q1=v1&q2=v2&custom_param1=3,4,5,6&custom_param2=value_custom_param2"
12
+ request.uri.to_s.should == 'https://api.grid5000.fr/sid/grid5000?q1=v1&q2=v2&custom_param1%5B%5D=3&custom_param1%5B%5D=4&custom_param1%5B%5D=5&custom_param1%5B%5D=6&custom_param2=value_custom_param2'
13
+ request.uri.query.should == "q1=v1&q2=v2&custom_param1%5B%5D=3&custom_param1%5B%5D=4&custom_param1%5B%5D=5&custom_param1%5B%5D=6&custom_param2=value_custom_param2"
14
14
  request.headers.should == {
15
15
  "Content-Type"=>"application/json",
16
16
  'Accept' => 'application/xml',
data/spec/spec_helper.rb CHANGED
@@ -1,12 +1,14 @@
1
1
  $LOAD_PATH.unshift(File.dirname(__FILE__))
2
2
  $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
3
+
4
+ require 'webmock/rspec'
5
+ include WebMock
6
+
3
7
  require 'restfully'
4
8
  require 'spec'
5
9
  require 'spec/autorun'
6
10
  require 'json'
7
11
 
8
- require 'webmock/rspec'
9
- include WebMock
10
12
 
11
13
  def fixture(filename)
12
14
  File.read(File.join(File.dirname(__FILE__), "fixtures", filename))
metadata CHANGED
@@ -1,7 +1,12 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: restfully
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.10
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 6
8
+ - 0
9
+ version: 0.6.0
5
10
  platform: ruby
6
11
  authors:
7
12
  - Cyril Rohr
@@ -9,69 +14,84 @@ autorequire:
9
14
  bindir: bin
10
15
  cert_chain: []
11
16
 
12
- date: 2010-04-20 00:00:00 +02:00
17
+ date: 2011-01-18 00:00:00 +01:00
13
18
  default_executable: restfully
14
19
  dependencies:
15
20
  - !ruby/object:Gem::Dependency
16
21
  name: rest-client
17
- type: :runtime
18
- version_requirement:
19
- version_requirements: !ruby/object:Gem::Requirement
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
20
24
  requirements:
21
25
  - - ">="
22
26
  - !ruby/object:Gem::Version
27
+ segments:
28
+ - 1
29
+ - 4
23
30
  version: "1.4"
24
- version:
31
+ type: :runtime
32
+ version_requirements: *id001
25
33
  - !ruby/object:Gem::Dependency
26
34
  name: json
27
- type: :runtime
28
- version_requirement:
29
- version_requirements: !ruby/object:Gem::Requirement
35
+ prerelease: false
36
+ requirement: &id002 !ruby/object:Gem::Requirement
30
37
  requirements:
31
38
  - - ">="
32
39
  - !ruby/object:Gem::Version
40
+ segments:
41
+ - 1
42
+ - 2
43
+ - 0
33
44
  version: 1.2.0
34
- version:
45
+ type: :runtime
46
+ version_requirements: *id002
35
47
  - !ruby/object:Gem::Dependency
36
48
  name: backports
37
- type: :runtime
38
- version_requirement:
39
- version_requirements: !ruby/object:Gem::Requirement
49
+ prerelease: false
50
+ requirement: &id003 !ruby/object:Gem::Requirement
40
51
  requirements:
41
52
  - - ">="
42
53
  - !ruby/object:Gem::Version
54
+ segments:
55
+ - 0
43
56
  version: "0"
44
- version:
57
+ type: :runtime
58
+ version_requirements: *id003
45
59
  - !ruby/object:Gem::Dependency
46
60
  name: webmock
47
- type: :development
48
- version_requirement:
49
- version_requirements: !ruby/object:Gem::Requirement
61
+ prerelease: false
62
+ requirement: &id004 !ruby/object:Gem::Requirement
50
63
  requirements:
51
64
  - - ">="
52
65
  - !ruby/object:Gem::Version
66
+ segments:
67
+ - 0
53
68
  version: "0"
54
- version:
69
+ type: :development
70
+ version_requirements: *id004
55
71
  - !ruby/object:Gem::Dependency
56
72
  name: rspec
57
- type: :development
58
- version_requirement:
59
- version_requirements: !ruby/object:Gem::Requirement
73
+ prerelease: false
74
+ requirement: &id005 !ruby/object:Gem::Requirement
60
75
  requirements:
61
76
  - - ">="
62
77
  - !ruby/object:Gem::Version
78
+ segments:
79
+ - 0
63
80
  version: "0"
64
- version:
81
+ type: :development
82
+ version_requirements: *id005
65
83
  - !ruby/object:Gem::Dependency
66
84
  name: json
67
- type: :development
68
- version_requirement:
69
- version_requirements: !ruby/object:Gem::Requirement
85
+ prerelease: false
86
+ requirement: &id006 !ruby/object:Gem::Requirement
70
87
  requirements:
71
88
  - - ">="
72
89
  - !ruby/object:Gem::Version
90
+ segments:
91
+ - 0
73
92
  version: "0"
74
- version:
93
+ type: :development
94
+ version_requirements: *id006
75
95
  description: Experimental code for auto-generation of wrappers on top of RESTful APIs that follow HATEOAS principles and provide OPTIONS methods and/or Allow headers.
76
96
  email: cyril.rohr@gmail.com
77
97
  executables:
@@ -139,18 +159,20 @@ required_ruby_version: !ruby/object:Gem::Requirement
139
159
  requirements:
140
160
  - - ">="
141
161
  - !ruby/object:Gem::Version
162
+ segments:
163
+ - 0
142
164
  version: "0"
143
- version:
144
165
  required_rubygems_version: !ruby/object:Gem::Requirement
145
166
  requirements:
146
167
  - - ">="
147
168
  - !ruby/object:Gem::Version
169
+ segments:
170
+ - 0
148
171
  version: "0"
149
- version:
150
172
  requirements: []
151
173
 
152
174
  rubyforge_project:
153
- rubygems_version: 1.3.5
175
+ rubygems_version: 1.3.6
154
176
  signing_key:
155
177
  specification_version: 3
156
178
  summary: Experimental code for auto-generation of wrappers on top of RESTful APIs that follow some specific conventions.