ananke 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc CHANGED
@@ -49,26 +49,103 @@ The Default Repository can be changed:
49
49
  ananke.default_repository = 'MyRepository'
50
50
 
51
51
  == HyperMedia
52
- Current HyperMedia support is very limited. The following example demostrates it's use:
52
+ === Linked
53
53
 
54
54
  rest :user do
55
55
  id :id
56
56
  linked :computer
57
57
  end
58
58
 
59
- To support the above example, the Respository for User needs to have a method that returns an
60
- array of id's for use in the HyperMedia links. The method signature is as follows
59
+ module Repository
60
+ module User
61
+ def self.one(id)
62
+ [Return User for User Id]
63
+ end
64
+ def self.computer_id_list(id)
65
+ [Return an array of single value id's]
66
+ end
67
+ end
68
+ end
69
+
70
+ Repository Method:
71
+
72
+ [ResourceRepository].[linked name]_id_list
61
73
 
62
- def self.computer_id_list
63
- [Return an array of single value id's]
74
+ Routes Available/Registered:
75
+
76
+ /user/:id
77
+
78
+ Output:
79
+
80
+ {
81
+ user: {
82
+ user_id: "1"
83
+ name: "One"
84
+ }
85
+ links: [
86
+ {
87
+ rel: "self"
88
+ uri: "/user/1"
89
+ },
90
+ {
91
+ rel: "computer"
92
+ uri: "/computer/2"
93
+ }
94
+ ]
95
+ }
96
+
97
+ The Respository for User needs to have a method that returns an array of id's for use in the HyperMedia links.
98
+ The link to <b>Self</b> uses this method. The output will be something like this:
99
+
100
+ === Link To and Route For
101
+
102
+ rest :user do
103
+ id :id
104
+ link_to :computer
105
+ end
106
+ rest :computer do
107
+ id :id
108
+ route_for :user
109
+ end
110
+
111
+ module Repository
112
+ module User
113
+ def self.one(id)
114
+ [Return User for User Id]
115
+ end
116
+ end
117
+ module Computer
118
+ def self.user(id)
119
+ [Return List of Computers for User Id]
120
+ end
121
+ end
64
122
  end
65
123
 
66
- It get called:
124
+ Routes Available/Registered:
125
+
126
+ /user/:id
127
+ /computer/user/:id
128
+
129
+ Output:
67
130
 
68
- [ResourceRepository].[link name]_id_list
131
+ {
132
+ user: {
133
+ user_id: "1"
134
+ name: "One"
135
+ }
136
+ links: [
137
+ {
138
+ rel: "self"
139
+ uri: "/user/1"
140
+ },
141
+ {
142
+ rel: "computer"
143
+ uri: "/computer/user/1"
144
+ }
145
+ ]
146
+ }
69
147
 
70
- We are working on adding lots more HyperMedia Support, especially to get around problems that
71
- the current HyperMedia is giving. Stay tuned...
148
+ This way of linking solves a lot of problems, and can also be used for searching support.
72
149
 
73
150
  == Media Type
74
151
  The REST media type can be built up:
@@ -128,7 +205,6 @@ A short list of future development:
128
205
  - Refactor!
129
206
  - Return Value Strategy
130
207
  - Resource Exposes Media Type
131
- - HyperMedia
132
208
  - Lots more `bullet-proofing`
133
209
  - ETag Support
134
210
 
data/Rakefile CHANGED
@@ -32,14 +32,14 @@ gemspec = Gem::Specification.new do |gem|
32
32
 
33
33
  **************************************************
34
34
  }
35
- gem.add_dependency "sinatra", "~> 1.1.2"
35
+ gem.add_dependency "sinatra", "~> 1.1.2"
36
+ gem.add_dependency "colored", "~> 1.2"
37
+ gem.add_dependency "json", "~> 1.5.1"
36
38
 
37
- gem.add_development_dependency "colored", "~> 1.2"
38
- gem.add_development_dependency "json", "~> 1.5.1"
39
- gem.add_development_dependency "rack-test", "~> 0.5.6"
40
- gem.add_development_dependency "rake", "~> 0.8.7"
41
- gem.add_development_dependency "rspec", "~> 2.5.0"
42
- gem.add_development_dependency "simplecov", "~> 0.3.9"
39
+ gem.add_development_dependency "rack-test", "~> 0.5.6"
40
+ gem.add_development_dependency "rake", "~> 0.8.7"
41
+ gem.add_development_dependency "rspec", "~> 2.5.0"
42
+ gem.add_development_dependency "simplecov", "~> 0.3.9"
43
43
  end
44
44
 
45
45
  Rake::GemPackageTask.new(gemspec) do |pkg|
data/lib/ananke.rb CHANGED
@@ -44,7 +44,7 @@ module Ananke
44
44
  mod
45
45
  end
46
46
 
47
- def get_json(path, obj)
47
+ def get_json(path, obj, links)
48
48
  if obj.nil?
49
49
  out :error, "#{path} - No return object"
50
50
  ''
@@ -52,10 +52,17 @@ module Ananke
52
52
  out :error, "#{path} - Return object cannot be converted to JSON"
53
53
  ''
54
54
  else
55
- obj.to_json
55
+ root_path = path.to_s.split('/')[0]
56
+ dic = {root_path.to_sym => obj}
57
+ dic[:links] = links unless links.nil?
58
+ dic.to_json
56
59
  end
57
60
  end
58
61
 
62
+ def get_id(obj, key)
63
+ obj.respond_to?(key) ? obj.instance_variable_get(key) : obj.class == Hash && obj.has_key?(key) ? obj[key] : nil
64
+ end
65
+
59
66
  #===========================BUILDUP============================
60
67
  def build_route(mod, mod_method, verb, route, &block)
61
68
  if mod.respond_to? mod_method
@@ -75,15 +82,17 @@ module Ananke
75
82
  end
76
83
  key = @id[:key]
77
84
  fields = @fields
78
- linkups = @linkups
85
+ link_list = @link_list
86
+ link_to_list = @link_to_list
87
+ route_for_list = @route_for_list
79
88
 
80
89
  #===========================GET/ID=============================
81
90
  build_route mod, :one, :get, "/#{path}/:#{key}" do
82
91
  param_missing!(key) if params[key].nil?
83
92
  obj = mod.one(params[key])
84
93
 
85
- json = get_json(path, obj)
86
- inject_links!(json, linkups, path, params[key], mod)
94
+ links = build_links(link_list, link_to_list, path, params[key], mod)
95
+ json = get_json(path, obj, links)
87
96
 
88
97
  status 200
89
98
  json
@@ -94,18 +103,24 @@ module Ananke
94
103
  obj_list = mod.all
95
104
 
96
105
  status 200
97
- json_list = []
106
+ #json_list = []
107
+ result_list = []
98
108
  obj_list.each do |obj|
99
- id = obj.respond_to?(key) ? obj.instance_variable_get(key) : obj.class == Hash && obj.has_key?(key) ? obj[key] : nil
109
+ id = get_id(obj, key)
100
110
  if !id.nil?
101
- json = get_json(path, obj)
102
- inject_links!(json, linkups, path, id, mod)
103
- json_list << json
111
+ dic = {path.to_sym => obj}
112
+ links = build_links(link_list, link_to_list, path, id, mod) if Ananke.settings[:links]
113
+ dic[:links] = links unless links.nil?
114
+ result_list << dic
104
115
  else
105
116
  out :error, "#{path} - Cannot find key(#{key}) on object #{obj}"
106
117
  end
107
118
  end
108
- "[#{json_list.join(',')}]"
119
+ dic = {"#{path}_list".to_sym => result_list}
120
+ link_self = build_link_self(path, '') if Ananke.settings[:links]
121
+ dic[:links] = link_self unless link_self.nil?
122
+
123
+ dic.to_json
109
124
  end
110
125
 
111
126
  #===========================POST===============================
@@ -114,8 +129,8 @@ module Ananke
114
129
  error status, message unless status.nil?
115
130
  obj = mod.add(params)
116
131
 
117
- json = get_json(path, obj)
118
- inject_links!(json, linkups, path, params[key], mod)
132
+ links = build_links(link_list, link_to_list, path, params[key], mod)
133
+ json = get_json(path, obj, links)
119
134
 
120
135
  status 201
121
136
  json
@@ -128,8 +143,8 @@ module Ananke
128
143
  error status, message unless status.nil?
129
144
  obj = mod.edit(params[key], params)
130
145
 
131
- json = get_json(path, obj)
132
- inject_links!(json, linkups, path, params[key], mod)
146
+ links = build_links(link_list, link_to_list, path, params[key], mod)
147
+ json = get_json(path, obj, links)
133
148
 
134
149
  status 200
135
150
  json
@@ -149,6 +164,20 @@ module Ananke
149
164
  build_route mod, :delete, :delete, "/#{path}/?" do
150
165
  param_missing!(key)
151
166
  end
167
+
168
+ #===========================ROUTE_FOR==========================
169
+ route_for_list.each do |r|
170
+ build_route mod, r[:name], :get, "/#{path}/#{r[:name]}/:key" do
171
+ param_missing!(:key) if params[:key].nil?
172
+ obj = mod.send(r[:name], params[:key])
173
+
174
+ links = build_links(link_list, link_to_list, "#{path}/#{r[:name]}", params[:key], mod)
175
+ json = get_json("#{path}/#{r[:name]}", obj, links)
176
+
177
+ status 200
178
+ json
179
+ end
180
+ end
152
181
  end
153
182
 
154
183
  #===========================Validation=========================
@@ -169,34 +198,51 @@ module Ananke
169
198
  error 400, "Missing Parameter: #{key.to_s}"
170
199
  end
171
200
 
172
- #===========================LINKING============================
173
- def build_links(path, id, mod, linkups)
174
- ret = [{:rel => 'self', :uri => "/#{path}/#{id}"}]
175
- linkups.each do |l|
201
+ #===========================LINKS==============================
202
+ def build_links(link_list, link_to_list, path, id, mod)
203
+ return if !Ananke.settings[:links]
204
+
205
+ links = build_link_self(path, id)
206
+ links += build_link_list(path, id, mod, link_list)
207
+ links += build_link_to_list(path, id, link_to_list)
208
+
209
+ links
210
+ end
211
+ #===========================SELF===============================
212
+ def build_link_self(path, id)
213
+ [{:rel => 'self', :uri => "/#{path}/#{id}"}]
214
+ end
215
+ #===========================LINKED=============================
216
+ def build_link_list(path, id, mod, link_list)
217
+ links = []
218
+ link_list.each do |l|
176
219
  mod_method = "#{l[:rel]}_id_list"
177
220
  if mod.respond_to?(mod_method)
178
221
  id_list = mod.send(mod_method, id)
179
- id_list.each{|i| ret << {:rel => "#{l[:rel]}", :uri => "/#{l[:rel]}/#{i}"}}
222
+ id_list.each{|i| links << {:rel => "#{l[:rel]}", :uri => "/#{l[:rel]}/#{i}"}}
180
223
  else
181
224
  out :error, "#{path} - #{mod} does not respond to '#{mod_method.to_s}'"
182
225
  end
183
226
  end
184
- ret
227
+ links
185
228
  end
186
-
187
- def inject_links!(json, linkups, path, id, mod)
188
- return if !Ananke.settings[:links]
189
- links = build_links(path, id, mod, linkups)
190
- json.insert(json.length-1, ",\"links\":#{links.to_json}")
229
+ #===========================LINK_TO============================
230
+ def build_link_to_list(path, id, link_to_list)
231
+ links = []
232
+ link_to_list.each do |l|
233
+ links << {:rel => "#{l[:rel]}", :uri => "/#{l[:rel]}/#{path}/#{id}"}
234
+ end
235
+ links
191
236
  end
192
237
 
193
238
  public
194
-
195
239
  #===========================DSL================================
196
240
  def rest(path, &block)
197
241
  @id = {}
198
242
  @fields = []
199
- @linkups = []
243
+ @link_list = []
244
+ @link_to_list = []
245
+ @route_for_list = []
200
246
  yield block
201
247
  build path
202
248
  end
@@ -210,8 +256,14 @@ module Ananke
210
256
  def optional(key, *rules)
211
257
  @fields << {:key => key, :type => :optional, :rules => rules}
212
258
  end
213
- def linkup(rel)
214
- @linkups << {:rel => rel}
259
+ def linked(rel)
260
+ @link_list << {:rel => rel}
261
+ end
262
+ def link_to(rel)
263
+ @link_to_list << {:rel => rel}
264
+ end
265
+ def route_for(rel)
266
+ @route_for_list << {:name => rel}
215
267
  end
216
268
  def rule(name, &block)
217
269
  Ananke::Rules.send(:define_singleton_method, "validate_#{name}", block)
data/lib/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Ananke
2
- VERSION = "0.0.2"
2
+ VERSION = "0.0.3"
3
3
  end
@@ -0,0 +1,31 @@
1
+ require './spec/spec_helper'
2
+ require './lib/ananke'
3
+
4
+ describe 'Link-To Resource' do
5
+ include Rack::Test::Methods
6
+ include Ananke
7
+
8
+ def app
9
+ Sinatra::Base
10
+ end
11
+
12
+ it """
13
+ Should be able to Output link to link_to
14
+ """ do
15
+ module Repository
16
+ module Link_to
17
+ def self.one(id)
18
+ {:link_id => id}
19
+ end
20
+ end
21
+ end
22
+ rest :link_to do
23
+ id :link_id
24
+ link_to :to
25
+ end
26
+
27
+ get "/link_to/1"
28
+ check_status(200)
29
+ last_response.body.should == '{"link_to":{"link_id":"1"},"links":[{"rel":"self","uri":"/link_to/1"},{"rel":"to","uri":"/to/link_to/1"}]}'
30
+ end
31
+ end
@@ -26,7 +26,7 @@ describe 'Resource' do
26
26
 
27
27
  post "/self", body={:user_id => 1, :username => '1234'}
28
28
  check_status(201)
29
- last_response.body.should == '{"user_id":1,"links":[{"rel":"self","uri":"/self/1"}]}'
29
+ last_response.body.should == '{"self":{"user_id":1},"links":[{"rel":"self","uri":"/self/1"}]}'
30
30
 
31
31
  hash = JSON.parse(last_response.body)
32
32
  uri = hash['links'].map{|l| l['uri'] if l['rel'] == 'self'}[0]
@@ -35,7 +35,7 @@ describe 'Resource' do
35
35
  end
36
36
 
37
37
  module Repository
38
- module Linkup
38
+ module Linked
39
39
  def self.one(id)
40
40
  {:user_id => 1}
41
41
  end
@@ -56,20 +56,20 @@ describe 'Resource' do
56
56
  def self.one(id) end
57
57
  end
58
58
  end
59
- rest :linkup do
59
+ rest :linked do
60
60
  id :user_id
61
- linkup :line
61
+ linked :line
62
62
  end
63
63
  rest :line do
64
64
  id :line_id
65
65
  end
66
66
 
67
67
  it """
68
- Should be able to Output links to linkups and Call those links
68
+ Should be able to Output links to linkeds and Call those links
69
69
  """ do
70
- post "/linkup", body={:user_id => 1, :username => '1234'}
70
+ post "/linked", body={:user_id => 1, :username => '1234'}
71
71
  check_status(201)
72
- last_response.body.should == '{"user_id":1,"links":[{"rel":"self","uri":"/linkup/1"},{"rel":"line","uri":"/line/1"},{"rel":"line","uri":"/line/2"}]}'
72
+ last_response.body.should == '{"linked":{"user_id":1},"links":[{"rel":"self","uri":"/linked/1"},{"rel":"line","uri":"/line/1"},{"rel":"line","uri":"/line/2"}]}'
73
73
 
74
74
  hash = JSON.parse(last_response.body)
75
75
  hash['links'].each do |l|
@@ -79,29 +79,29 @@ describe 'Resource' do
79
79
  end
80
80
 
81
81
  it "Should return links on Get One" do
82
- #get "/linkup/1"
83
- #check_status(200)
84
- #last_response.body.should == '{"user_id":1,"links":[{"rel":"self","uri":"/linkup/1"},{"rel":"line","uri":"/line/1"},{"rel":"line","uri":"/line/2"}]}'
82
+ get "/linked/1"
83
+ check_status(200)
84
+ last_response.body.should == '{"linked":{"user_id":1},"links":[{"rel":"self","uri":"/linked/1"},{"rel":"line","uri":"/line/1"},{"rel":"line","uri":"/line/2"}]}'
85
85
  end
86
86
 
87
87
  it """
88
88
  Should not inject links where it cannot find Repository Id lookup method
89
89
  """ do
90
90
  module Repository
91
- module Linkup_fail
91
+ module Linked_fail
92
92
  def self.one(id) end
93
93
  def self.add(data)
94
94
  {:user_id => 1}
95
95
  end
96
96
  end
97
97
  end
98
- rest :linkup_fail do
98
+ rest :linked_fail do
99
99
  id :user_id
100
- linkup :line
100
+ linked :line
101
101
  end
102
102
 
103
- post "/linkup_fail", body={:user_id => 1, :username => '1234'}
103
+ post "/linked_fail", body={:user_id => 1, :username => '1234'}
104
104
  check_status(201)
105
- last_response.body.should == '{"user_id":1,"links":[{"rel":"self","uri":"/linkup_fail/1"}]}'
105
+ last_response.body.should == '{"linked_fail":{"user_id":1},"links":[{"rel":"self","uri":"/linked_fail/1"}]}'
106
106
  end
107
107
  end
@@ -0,0 +1,31 @@
1
+ require './spec/spec_helper'
2
+ require './lib/ananke'
3
+
4
+ describe 'Resource Route-For' do
5
+ include Rack::Test::Methods
6
+ include Ananke
7
+
8
+ def app
9
+ Sinatra::Base
10
+ end
11
+
12
+ it """
13
+ Should be able to accept route_for Registrations
14
+ """ do
15
+ module Repository
16
+ module Route_for
17
+ def self.custom(id)
18
+ {:content => 'Test'}
19
+ end
20
+ end
21
+ end
22
+ rest :route_for do
23
+ id :link_id
24
+ route_for :custom
25
+ end
26
+
27
+ get "/route_for/custom/1"
28
+ check_status(200)
29
+ last_response.body.should == '{"route_for":{"content":"Test"},"links":[{"rel":"self","uri":"/route_for/custom/1"}]}'
30
+ end
31
+ end
@@ -60,41 +60,41 @@ describe 'Basic Ananke REST' do
60
60
  """ do
61
61
  get "/user"
62
62
  check_status(200)
63
- last_response.body.should == Repository::User.data.to_json
63
+ last_response.body.should == '{"user_list":[{"user":{"user_id":1,"username":"one"}},{"user":{"user_id":2,"username":"two"}}]}'
64
64
  end
65
65
 
66
66
  it """
67
67
  GET /user/1
68
68
  - code: 200
69
69
  - content-type: text/plain
70
- - body: {user_id: ,username: ,email: ,country: }
70
+ - body: {user_id: ,username: }
71
71
  """ do
72
72
  get "/user/1"
73
73
  check_status(200)
74
- last_response.body.should == Repository::User.data[0].to_json
74
+ last_response.body.should == '{"user":{"user_id":1,"username":"one"}}'
75
75
  end
76
76
 
77
77
  it """
78
78
  POST /user
79
- - body: {user_id: ,username: ,email: ,country: }
79
+ - body: {user_id: ,username: }
80
80
  RETURN
81
81
  - code: 201
82
82
  - content-type: text/json
83
83
  - body:
84
84
  """ do
85
- post "/user", body={:user_id => 3, :username => 'three', :email => '3@three.com', :country => 'USA'}
85
+ post "/user", body={:user_id => 3, :username => 'three'}
86
86
  check_status(201)
87
87
  end
88
88
 
89
89
  it """
90
90
  PUT /user/3
91
- - body: {user_id: ,username: ,email: ,country: }
91
+ - body: {user_id: ,username: }
92
92
  RETURN
93
93
  - code: 200
94
94
  - content-type: text/json
95
95
  - body:
96
96
  """ do
97
- put "/user/3", body={:user_id => 3, :username => 'four', :email => '4@four.com', :country => 'Russia'}
97
+ put "/user/3", body={:user_id => 3, :username => 'four'}
98
98
  check_status(200)
99
99
  end
100
100
 
@@ -112,13 +112,13 @@ describe 'Basic Ananke REST' do
112
112
  #----------------------------FAILS--------------------------------------
113
113
  it """
114
114
  PUT /user
115
- - body: {user_id: ,username: ,email: ,country: }
115
+ - body: {user_id: ,username: }
116
116
  RETURN
117
117
  - code: 400
118
118
  - content-type: text/json
119
119
  - body: Missing Parameter: user_id
120
120
  """ do
121
- put "/user", body={:user_id => 3, :username => 'four', :email => '4@four.com', :country => 'Russia'}
121
+ put "/user", body={:user_id => 3, :username => 'four'}
122
122
  check_status(400)
123
123
  last_response.body.should == 'Missing Parameter: user_id'
124
124
  end
@@ -138,8 +138,8 @@ end
138
138
 
139
139
  module Repository
140
140
  module User
141
- @data = [{:user_id => 1, :username => 'one', :email => '1@one.com', :country => 'South Africa'},
142
- {:user_id => 2, :username => 'two', :email => '2@two.com', :country => 'England'}]
141
+ @data = [{:user_id => 1, :username => 'one'},
142
+ {:user_id => 2, :username => 'two'}]
143
143
 
144
144
  def self.data
145
145
  @data
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: ananke
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.0.2
5
+ version: 0.0.3
6
6
  platform: ruby
7
7
  authors:
8
8
  - Andries Coetzee
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2011-02-10 00:00:00 +02:00
13
+ date: 2011-02-11 00:00:00 +02:00
14
14
  default_executable:
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
@@ -33,7 +33,7 @@ dependencies:
33
33
  - - ~>
34
34
  - !ruby/object:Gem::Version
35
35
  version: "1.2"
36
- type: :development
36
+ type: :runtime
37
37
  version_requirements: *id002
38
38
  - !ruby/object:Gem::Dependency
39
39
  name: json
@@ -44,7 +44,7 @@ dependencies:
44
44
  - - ~>
45
45
  - !ruby/object:Gem::Version
46
46
  version: 1.5.1
47
- type: :development
47
+ type: :runtime
48
48
  version_requirements: *id003
49
49
  - !ruby/object:Gem::Dependency
50
50
  name: rack-test
@@ -104,9 +104,11 @@ files:
104
104
  - spec/dumping.rb
105
105
  - spec/cov_adapter.rb
106
106
  - spec/lib/ananke_spec.rb
107
+ - spec/lib/ananke_linked_spec.rb
107
108
  - spec/lib/ananke_out_spec.rb
108
- - spec/lib/ananke_links_spec.rb
109
109
  - spec/lib/validation_spec.rb
110
+ - spec/lib/ananke_link_to_spec.rb
111
+ - spec/lib/ananke_route_for_spec.rb
110
112
  - spec/spec_helper.rb
111
113
  - spec/call_chain.rb
112
114
  - spec/nice_formatter.rb
@@ -120,7 +122,7 @@ licenses: []
120
122
  post_install_message: |
121
123
  **************************************************
122
124
 
123
- Thank you for installing ananke-0.0.2
125
+ Thank you for installing ananke-0.0.3
124
126
 
125
127
  Please be sure to look at README.rdoc to see what might have changed
126
128
  since the last release and how to use this GEM.
@@ -149,14 +151,16 @@ rubyforge_project:
149
151
  rubygems_version: 1.5.0
150
152
  signing_key:
151
153
  specification_version: 3
152
- summary: ananke-0.0.2
154
+ summary: ananke-0.0.3
153
155
  test_files:
154
156
  - spec/dumping.rb
155
157
  - spec/cov_adapter.rb
156
158
  - spec/lib/ananke_spec.rb
159
+ - spec/lib/ananke_linked_spec.rb
157
160
  - spec/lib/ananke_out_spec.rb
158
- - spec/lib/ananke_links_spec.rb
159
161
  - spec/lib/validation_spec.rb
162
+ - spec/lib/ananke_link_to_spec.rb
163
+ - spec/lib/ananke_route_for_spec.rb
160
164
  - spec/spec_helper.rb
161
165
  - spec/call_chain.rb
162
166
  - spec/nice_formatter.rb