path-to 0.3.1 → 0.4.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/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
|