path-to 0.3.1 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +4 -0
- data/README.rdoc +10 -3
- data/Rakefile +1 -1
- data/examples/delicious.rb +3 -4
- data/lib/path-to.rb +1 -1
- data/lib/path-to/described_routes.rb +69 -15
- data/lib/path-to/with_params.rb +27 -0
- data/test/path-to/test_described_routes.rb +15 -6
- metadata +3 -3
data/History.txt
CHANGED
data/README.rdoc
CHANGED
@@ -18,10 +18,17 @@ Create a client application configured from a server that supports described_rou
|
|
18
18
|
|
19
19
|
app = PathTo::DescribedRoutes::Application.new(:json => Net::HTTP.get(URI.parse("http://example.com/described_routes.json")))
|
20
20
|
|
21
|
-
app.users["
|
22
|
-
|
21
|
+
app.users["dojo"].articles.recent
|
22
|
+
#=> http://example.com/users/dojo/articles/recent
|
23
|
+
app.users["dojo"].articles.recent.get
|
24
|
+
#=> "<html>...</html>"
|
25
|
+
|
26
|
+
app.users["dojo"].articles.recent["format" => "json"]
|
27
|
+
#=> http://example.com/users/dojo/articles/recent.json
|
28
|
+
app.users["dojo"].articles.recent.get
|
29
|
+
#=> [...]
|
23
30
|
|
24
|
-
See examples/delicious.rb for an example based on a partial YAML-based description of the Delicious API
|
31
|
+
See examples/delicious.rb for an example based on a partial YAML-based description of the Delicious API.
|
25
32
|
|
26
33
|
=== Local configuration
|
27
34
|
|
data/Rakefile
CHANGED
@@ -13,7 +13,7 @@ $hoe = Hoe.new('path-to', PathTo::VERSION) do |p|
|
|
13
13
|
p.extra_deps = [
|
14
14
|
['httparty','>= 0.4.2'],
|
15
15
|
['addressable','>= 2.0.2'],
|
16
|
-
['described_routes','>= 0.3.
|
16
|
+
['described_routes','>= 0.3.6']
|
17
17
|
]
|
18
18
|
p.extra_dev_deps = [
|
19
19
|
['newgem', ">= #{::Newgem::VERSION}"]
|
data/examples/delicious.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
|
-
# Adapted from jnunemaker/httparty/examples/delicious.rb to demonstrate path-to's metadata-driven
|
2
|
-
# For more information see http://positiveincline.com/?tag=path-to
|
1
|
+
# Adapted from jnunemaker/httparty/examples/delicious.rb to demonstrate path-to's metadata-driven client API capability
|
3
2
|
|
4
3
|
require 'path-to/described_routes'
|
5
4
|
require 'pp'
|
@@ -38,6 +37,6 @@ delicious = PathTo::DescribedRoutes::Application.new(
|
|
38
37
|
:username => config['username'],
|
39
38
|
:password => config['password']}})
|
40
39
|
|
41
|
-
pp delicious.posts
|
42
|
-
pp delicious.posts
|
40
|
+
pp delicious.posts('ruby').get
|
41
|
+
pp delicious.posts('ruby').recent('count' => '5').get
|
43
42
|
delicious.recent_posts.get['posts']['post'].each { |post| puts post['href'] }
|
data/lib/path-to.rb
CHANGED
@@ -2,10 +2,26 @@ require "path-to"
|
|
2
2
|
require "described_routes/resource_template"
|
3
3
|
|
4
4
|
module PathTo
|
5
|
+
#
|
6
|
+
# Application and Path implementations for DescribedRoutes, each resource described by a ResourceTemplate
|
7
|
+
#
|
5
8
|
module DescribedRoutes
|
9
|
+
#
|
10
|
+
# Implements PathTo::Path, represents a resource described by a ResourceTemplate
|
11
|
+
#
|
6
12
|
class TemplatedPath < PathTo::Path
|
7
13
|
attr_reader :resource_template
|
8
14
|
|
15
|
+
#
|
16
|
+
# Initialize a TemplatedPath. Raises ArgumentError if params doesn't include all mandatory params expected by the resource
|
17
|
+
# template.
|
18
|
+
#
|
19
|
+
# Parameters:
|
20
|
+
# [parent] parent object path or application
|
21
|
+
# [service] unused - resource_template.name is passed to super() instead. TODO: refactor
|
22
|
+
# [params] hash of params; will be merged with the parent's params and passed when required to the resource template's URI template
|
23
|
+
# [resource_template] metadata describing the web resource
|
24
|
+
#
|
9
25
|
def initialize(parent, service, params, resource_template)
|
10
26
|
super(parent, resource_template.name, params)
|
11
27
|
@resource_template = resource_template
|
@@ -20,10 +36,16 @@ module PathTo
|
|
20
36
|
end
|
21
37
|
end
|
22
38
|
|
39
|
+
#
|
40
|
+
# Get and cache the uri template from the resource tamplte
|
41
|
+
#
|
23
42
|
def uri_template
|
24
43
|
@uri_template ||= resource_template.uri_template || (application.base + resource_template.path_template)
|
25
44
|
end
|
26
45
|
|
46
|
+
#
|
47
|
+
# Create and cache the URI by filling in the URI template with params
|
48
|
+
#
|
27
49
|
def uri
|
28
50
|
@uri ||= begin
|
29
51
|
Addressable::Template.new(uri_template).expand(params).to_s
|
@@ -43,15 +65,38 @@ module PathTo
|
|
43
65
|
end
|
44
66
|
|
45
67
|
#
|
46
|
-
# Creates a child instance with new params, potentially finding a nested resource template that takes the additional params
|
68
|
+
# Creates a child instance with new params, potentially finding a nested resource template that takes the additional params.
|
69
|
+
# May take a combination of positional and named parameters, e.g.
|
70
|
+
#
|
71
|
+
# users["dojo", {"format" => "json"}]
|
47
72
|
#
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
73
|
+
# Positional parameters are unsupported however if a new child template is not identified.
|
74
|
+
#
|
75
|
+
def [](*args)
|
76
|
+
positional_params, params_hash = extract_params(args, params)
|
77
|
+
known_keys = params_hash.keys
|
78
|
+
|
79
|
+
child_resource_template = resource_template.resource_templates.detect do |t|
|
80
|
+
if t.rel.nil?
|
81
|
+
(t.positional_params(resource_template)[positional_params.length..-1] - t.optional_params - known_keys).empty?
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
if child_resource_template
|
86
|
+
# we have a new child resource template; apply any positional params to the hash
|
87
|
+
complete_params_hash!(params_hash, child_resource_template.positional_params(resource_template), positional_params)
|
88
|
+
else
|
89
|
+
# we're just adding optional params, no new template identified
|
90
|
+
unless positional_params.empty?
|
91
|
+
raise ArgumentError.new(
|
92
|
+
"No matching child template; only named parameters can be used here. " +
|
93
|
+
"positional_params=#{positional_params.inspect}, params_hash=#{params_hash.inspect}")
|
94
|
+
end
|
95
|
+
child_resource_template = resource_template
|
96
|
+
end
|
97
|
+
|
98
|
+
child_class = child_class_for(self, nil, params_hash, child_resource_template)
|
99
|
+
child(child_class, nil, params_hash, child_resource_template)
|
55
100
|
end
|
56
101
|
|
57
102
|
#
|
@@ -62,11 +107,16 @@ module PathTo
|
|
62
107
|
#
|
63
108
|
# Otherwise we invoke super in the hope of avoiding any hard-to-debug behaviour!
|
64
109
|
#
|
110
|
+
# May take a combination of positional and named parameters, e.g.
|
111
|
+
#
|
112
|
+
# users("dojo", "format" => "json")
|
113
|
+
#
|
65
114
|
def method_missing(method, *args)
|
66
115
|
child_resource_template = resource_template.resource_templates.detect{|t| t.rel == method.to_s}
|
67
116
|
if child_resource_template && (child_class = child_class_for(self, method, params, child_resource_template))
|
68
|
-
|
69
|
-
|
117
|
+
positional_params, params_hash = extract_params(args, params)
|
118
|
+
complete_params_hash!(params_hash, child_resource_template.positional_params(resource_template), positional_params)
|
119
|
+
child(child_class, method, params_hash, child_resource_template)
|
70
120
|
else
|
71
121
|
super
|
72
122
|
end
|
@@ -74,6 +124,9 @@ module PathTo
|
|
74
124
|
|
75
125
|
end
|
76
126
|
|
127
|
+
#
|
128
|
+
# DescribedRoutes implementation of PathTo::Application.
|
129
|
+
#
|
77
130
|
class Application < WithParams
|
78
131
|
# An Array of DescribedRoutes::Resource objects
|
79
132
|
attr_reader :resource_templates
|
@@ -122,7 +175,7 @@ module PathTo
|
|
122
175
|
#
|
123
176
|
# Creates a copy of self with additional params
|
124
177
|
#
|
125
|
-
def [](params
|
178
|
+
def [](params)
|
126
179
|
self.class.new(:parent => self, :params => params)
|
127
180
|
end
|
128
181
|
|
@@ -135,10 +188,11 @@ module PathTo
|
|
135
188
|
# Otherwise we invoke super in the hope of avoiding any hard-to-debug behaviour!
|
136
189
|
#
|
137
190
|
def method_missing(method, *args)
|
138
|
-
|
139
|
-
if
|
140
|
-
|
141
|
-
|
191
|
+
child_resource_template = resource_templates_by_name[method.to_s]
|
192
|
+
if child_resource_template && (child_class = child_class_for(self, method, params, child_resource_template))
|
193
|
+
positional_params, params_hash = extract_params(args, params)
|
194
|
+
complete_params_hash!(params_hash, child_resource_template.positional_params(nil), positional_params)
|
195
|
+
child(child_class, method, params_hash, child_resource_template)
|
142
196
|
else
|
143
197
|
super
|
144
198
|
end
|
data/lib/path-to/with_params.rb
CHANGED
@@ -87,5 +87,32 @@ module PathTo
|
|
87
87
|
super
|
88
88
|
end
|
89
89
|
end
|
90
|
+
|
91
|
+
#
|
92
|
+
# Separates positional params from hash params
|
93
|
+
# TODO: this is initially just for the DescribedRoutes implementation but there will be some refactoring to do
|
94
|
+
#
|
95
|
+
def extract_params(args, params_hash={})#:nodoc:
|
96
|
+
positional_params = []
|
97
|
+
params_hash = params_hash.clone
|
98
|
+
args.each do |arg|
|
99
|
+
if arg.kind_of?(Hash)
|
100
|
+
params_hash.merge!(arg)
|
101
|
+
else
|
102
|
+
positional_params << arg
|
103
|
+
end
|
104
|
+
end
|
105
|
+
[positional_params, params_hash]
|
106
|
+
end
|
107
|
+
|
108
|
+
#
|
109
|
+
# Updates params_hash with positional parameters
|
110
|
+
# TODO: this is initially just for the DescribedRoutes implementation but there will be some refactoring to do
|
111
|
+
#
|
112
|
+
def complete_params_hash!(params_hash, names, values)#:nodoc:
|
113
|
+
names[0...values.length].each_with_index do |k, i|
|
114
|
+
params_hash[k] = values[i]
|
115
|
+
end
|
116
|
+
end
|
90
117
|
end
|
91
118
|
end
|
@@ -102,13 +102,22 @@ class TestDescribedRoutes < Test::Unit::TestCase
|
|
102
102
|
end
|
103
103
|
|
104
104
|
def test_path_optional_params
|
105
|
-
|
106
|
-
|
105
|
+
# more complicated than would be ideal, but the app has a different #method_missing d
|
106
|
+
user_articles = app.users["user_id" => "dojo"].articles("json")
|
107
107
|
|
108
|
-
assert_equal("
|
109
|
-
assert_equal("
|
110
|
-
|
111
|
-
|
108
|
+
assert_equal("user_articles", user_articles.service)
|
109
|
+
assert_equal({"user_id" => "dojo", "format" => "json"}, user_articles.params)
|
110
|
+
end
|
111
|
+
|
112
|
+
def test_path_collection_positional_params
|
113
|
+
article_json = app.users["dojo"].articles["article-1"]["format" => "json"]
|
114
|
+
assert_equal("user_article", article_json.service)
|
115
|
+
assert_equal({"user_id" => "dojo", "article_id" => "article-1", "format" => "json"}, article_json.params)
|
116
|
+
assert_equal("http://localhost:3000/users/dojo/articles/article-1.json", article_json.uri)
|
117
|
+
|
118
|
+
assert_raises(ArgumentError) do
|
119
|
+
article_json = app.users["dojo"]["json"]
|
120
|
+
end
|
112
121
|
end
|
113
122
|
|
114
123
|
def test_app_params
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: path-to
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mike Burrows (asplake)
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-05-
|
12
|
+
date: 2009-05-12 00:00:00 +01:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -40,7 +40,7 @@ dependencies:
|
|
40
40
|
requirements:
|
41
41
|
- - ">="
|
42
42
|
- !ruby/object:Gem::Version
|
43
|
-
version: 0.3.
|
43
|
+
version: 0.3.6
|
44
44
|
version:
|
45
45
|
- !ruby/object:Gem::Dependency
|
46
46
|
name: newgem
|