restfully 0.5.10 → 0.6.0

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 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.