ananke 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +2 -2
- data/README.rdoc +6 -6
- data/lib/ananke/helpers.rb +42 -0
- data/lib/ananke/routing.rb +19 -23
- data/lib/ananke/validation.rb +1 -1
- data/lib/ananke.rb +1 -1
- data/lib/version.rb +1 -1
- data/spec/lib/ananke_spec.rb +16 -14
- data/spec/lib/json_spec.rb +51 -0
- data/spec/lib/link_to_spec.rb +1 -1
- data/spec/lib/linked_spec.rb +4 -4
- data/spec/lib/route_for_spec.rb +2 -2
- data/spec/lib/validation_spec.rb +3 -3
- metadata +19 -17
data/Gemfile
CHANGED
@@ -4,12 +4,12 @@ gem "colored", "~>1.2"
|
|
4
4
|
gem "json", "~>1.5.1"
|
5
5
|
gem "sinatra", "~>1.1.2"
|
6
6
|
|
7
|
-
group :development, :test do
|
7
|
+
#group :development, :test do
|
8
8
|
gem "rack-test", "~>0.5.6"
|
9
9
|
gem "rake", "~>0.8.7"
|
10
10
|
gem "rspec", "~>2.5.0"
|
11
11
|
gem 'simplecov', '~>0.4.0'
|
12
|
-
end
|
12
|
+
#end
|
13
13
|
|
14
14
|
|
15
15
|
|
data/README.rdoc
CHANGED
@@ -19,7 +19,7 @@ Ananke is a DSL that extends the functionality of Sinatra for easy creation of R
|
|
19
19
|
end
|
20
20
|
end
|
21
21
|
#-------------------REST Resources--------------------
|
22
|
-
|
22
|
+
route :user do
|
23
23
|
id :id
|
24
24
|
end
|
25
25
|
|
@@ -34,7 +34,7 @@ One User
|
|
34
34
|
http://localhost:4567/user/1
|
35
35
|
|
36
36
|
== REST Resources
|
37
|
-
`
|
37
|
+
`route` defines a complete Resource, and constructs Sinatra Routes
|
38
38
|
based on what's available in it's respective Repository. Routes are:
|
39
39
|
|
40
40
|
get '/name/?' -> Repository::Capitalize(name).all
|
@@ -51,7 +51,7 @@ The Default Repository can be changed:
|
|
51
51
|
== HyperMedia
|
52
52
|
=== Linked
|
53
53
|
|
54
|
-
|
54
|
+
route :user do
|
55
55
|
id :id
|
56
56
|
linked :computer
|
57
57
|
end
|
@@ -99,11 +99,11 @@ The link to <b>Self</b> uses this method. The output will be something like this
|
|
99
99
|
|
100
100
|
=== Link To and Route For
|
101
101
|
|
102
|
-
|
102
|
+
route :user do
|
103
103
|
id :id
|
104
104
|
link_to :car
|
105
105
|
end
|
106
|
-
|
106
|
+
route :car do
|
107
107
|
id :id
|
108
108
|
route_for :user
|
109
109
|
end
|
@@ -148,7 +148,7 @@ Output:
|
|
148
148
|
This way of linking solves a lot of problems, and can also be used for searching support.
|
149
149
|
<b>route_for</b> supports an optional 2nd parameter to specify the type of request it must register for:
|
150
150
|
|
151
|
-
|
151
|
+
route :car do
|
152
152
|
id :id
|
153
153
|
route_for :user, :post
|
154
154
|
end
|
data/lib/ananke/helpers.rb
CHANGED
@@ -40,4 +40,46 @@ module Ananke
|
|
40
40
|
puts message unless message.nil?
|
41
41
|
message
|
42
42
|
end
|
43
|
+
|
44
|
+
def symbolize_keys(hash)
|
45
|
+
new_hash = {}
|
46
|
+
hash.each{|k,v| new_hash[k.to_sym] = Hash === v ? symbolize_keys(v) : v}
|
47
|
+
new_hash
|
48
|
+
end
|
49
|
+
|
50
|
+
def collect_params(params)
|
51
|
+
new_params = {}
|
52
|
+
params.each do |k,v|
|
53
|
+
json = symbolize_keys(JSON.parse(k)) if v.nil?
|
54
|
+
if !json.nil? && !json.empty?
|
55
|
+
new_params.merge!(json)
|
56
|
+
else
|
57
|
+
new_params[k.to_sym] = v
|
58
|
+
end
|
59
|
+
end
|
60
|
+
new_params
|
61
|
+
end
|
62
|
+
|
63
|
+
def define_repository_call(mod, method_name)
|
64
|
+
inputs = mod.method(method_name).parameters
|
65
|
+
repository_name = mod.name.split('::').last
|
66
|
+
call_def = "def self.call_#{repository_name}_#{method_name}(params)"
|
67
|
+
case inputs.length
|
68
|
+
when 0
|
69
|
+
call_def << "#{mod}.send(:#{method_name})"
|
70
|
+
when 1
|
71
|
+
call_def << "#{mod}.send(:#{method_name}, params[:key])"
|
72
|
+
else
|
73
|
+
input_array = []
|
74
|
+
inputs.each{|i| input_array << "params[:#{i[1]}]"}
|
75
|
+
call_def << "#{mod}.send(:#{method_name}, #{input_array.join(',')})"
|
76
|
+
end
|
77
|
+
call_def << "end"
|
78
|
+
Ananke.send(:eval, call_def)
|
79
|
+
end
|
80
|
+
|
81
|
+
def repository_call(mod, method_name, params)
|
82
|
+
repository_name = mod.name.split('::').last
|
83
|
+
Ananke.send("call_#{repository_name}_#{method_name}", params)
|
84
|
+
end
|
43
85
|
end
|
data/lib/ananke/routing.rb
CHANGED
@@ -1,3 +1,7 @@
|
|
1
|
+
require './lib/ananke/validation'
|
2
|
+
require './lib/ananke/linking'
|
3
|
+
require './lib/ananke/helpers'
|
4
|
+
|
1
5
|
module Ananke
|
2
6
|
public
|
3
7
|
class << self
|
@@ -14,6 +18,7 @@ module Ananke
|
|
14
18
|
|
15
19
|
def build_route(mod, mod_method, verb, route, &block)
|
16
20
|
if mod.respond_to? mod_method
|
21
|
+
define_repository_call(mod, mod_method)
|
17
22
|
add_route(route.split('/')[1], mod_method)
|
18
23
|
Sinatra::Base.send verb, "#{route}", do
|
19
24
|
instance_eval(&block)
|
@@ -74,11 +79,13 @@ module Ananke
|
|
74
79
|
|
75
80
|
#===========================POST===============================
|
76
81
|
build_route mod, :add, :post, "/#{path}/?" do
|
77
|
-
|
82
|
+
new_params = collect_params(params)
|
83
|
+
status, message = validate(fields, new_params)
|
78
84
|
error status, message unless status.nil?
|
79
|
-
|
85
|
+
|
86
|
+
obj = repository_call(mod, :add, new_params)
|
80
87
|
|
81
|
-
links = build_links(link_list, link_to_list, path,
|
88
|
+
links = build_links(link_list, link_to_list, path, new_params[key], mod)
|
82
89
|
json = get_json(path, obj, links)
|
83
90
|
|
84
91
|
status 201
|
@@ -87,10 +94,12 @@ module Ananke
|
|
87
94
|
|
88
95
|
#===========================PUT================================
|
89
96
|
build_route mod, :edit, :put, "/#{path}/:#{key}" do
|
90
|
-
|
91
|
-
|
97
|
+
new_params = collect_params(params)
|
98
|
+
param_missing!(key) if new_params[key].nil?
|
99
|
+
status, message = validate(fields, new_params)
|
92
100
|
error status, message unless status.nil?
|
93
|
-
|
101
|
+
|
102
|
+
obj = repository_call(mod, :edit, new_params)
|
94
103
|
|
95
104
|
links = build_links(link_list, link_to_list, path, params[key], mod)
|
96
105
|
json = get_json(path, obj, links)
|
@@ -120,24 +129,11 @@ module Ananke
|
|
120
129
|
full_path = "/#{path}/#{r[:name]}"
|
121
130
|
full_path << "/:key" if inputs.length == 1
|
122
131
|
|
123
|
-
call_def = "def self.call_#{path}_#{r[:name]}(params)"
|
124
|
-
case inputs.length
|
125
|
-
when 0
|
126
|
-
call_def << "#{mod}.send(:#{r[:name]})"
|
127
|
-
when 1
|
128
|
-
call_def << "#{mod}.send(:#{r[:name]}, params[:key])"
|
129
|
-
else
|
130
|
-
input_array = []
|
131
|
-
inputs.each{|i| input_array << "params[:#{i[1]}]"}
|
132
|
-
call_def << "#{mod}.send(:#{r[:name]}, #{input_array.join(',')})"
|
133
|
-
end
|
134
|
-
call_def << "end"
|
135
|
-
puts call_def
|
136
|
-
Ananke.send(:eval, call_def)
|
137
|
-
|
138
132
|
build_route mod, r[:name], r[:verb], full_path do
|
139
|
-
|
140
|
-
|
133
|
+
new_params = collect_params(params)
|
134
|
+
param_missing!(:key) if inputs.length == 1 && new_params[:key].nil?
|
135
|
+
|
136
|
+
obj = repository_call(mod, r[:name], new_params)
|
141
137
|
|
142
138
|
links = build_links(link_list, link_to_list, "#{path}/#{r[:name]}", params[:key], mod)
|
143
139
|
json = get_json("#{path}/#{r[:name]}", obj, links)
|
data/lib/ananke/validation.rb
CHANGED
@@ -10,7 +10,7 @@ module Ananke
|
|
10
10
|
def validate(fields, params)
|
11
11
|
errors = []
|
12
12
|
fields.each do |field|
|
13
|
-
value = params[field[:key]
|
13
|
+
value = params[field[:key]]
|
14
14
|
errors << "Missing Required Parameter: #{field[:key]}" if field[:type] == :required && value.nil?
|
15
15
|
Ananke::Rules.value = value
|
16
16
|
field[:rules].each do |r|
|
data/lib/ananke.rb
CHANGED
data/lib/version.rb
CHANGED
data/spec/lib/ananke_spec.rb
CHANGED
@@ -21,7 +21,7 @@ describe 'Basic Ananke REST' do
|
|
21
21
|
it """
|
22
22
|
Should be able to describe a Valid REST Resource
|
23
23
|
""" do
|
24
|
-
|
24
|
+
route :user do
|
25
25
|
id :user_id
|
26
26
|
end
|
27
27
|
end
|
@@ -29,7 +29,7 @@ describe 'Basic Ananke REST' do
|
|
29
29
|
it """
|
30
30
|
Should skip creating Routes for Non-Existing Repositories
|
31
31
|
""" do
|
32
|
-
|
32
|
+
route :invalid do
|
33
33
|
end
|
34
34
|
end
|
35
35
|
|
@@ -104,7 +104,7 @@ describe 'Basic Ananke REST' do
|
|
104
104
|
- content-type: text/json
|
105
105
|
- body:
|
106
106
|
""" do
|
107
|
-
put "/user/3", body={:
|
107
|
+
put "/user/3", body={:username => 'four'}
|
108
108
|
check_status(200)
|
109
109
|
end
|
110
110
|
|
@@ -128,7 +128,7 @@ describe 'Basic Ananke REST' do
|
|
128
128
|
- content-type: text/json
|
129
129
|
- body: Missing Parameter: user_id
|
130
130
|
""" do
|
131
|
-
put "/user", body={:
|
131
|
+
put "/user", body={:username => 'four'}
|
132
132
|
check_status(400)
|
133
133
|
last_response.body.should == 'Missing Parameter: user_id'
|
134
134
|
end
|
@@ -155,22 +155,24 @@ module Repository
|
|
155
155
|
@data
|
156
156
|
end
|
157
157
|
|
158
|
-
def self.one(
|
159
|
-
@data[@data.index{ |d| d[:user_id] ==
|
158
|
+
def self.one(user_id)
|
159
|
+
@data[@data.index{ |d| d[:user_id] == user_id.to_i}]
|
160
160
|
end
|
161
161
|
def self.all
|
162
162
|
@data
|
163
163
|
end
|
164
|
-
def self.add(
|
165
|
-
|
166
|
-
data
|
164
|
+
def self.add(user_id, username)
|
165
|
+
obj = {:user_id => user_id.to_i, :username => username}
|
166
|
+
@data << obj
|
167
|
+
obj
|
167
168
|
end
|
168
|
-
def self.edit(
|
169
|
-
|
170
|
-
data
|
169
|
+
def self.edit(user_id, username)
|
170
|
+
obj = {:user_id => user_id.to_i, :username => username}
|
171
|
+
@data[@data.index{|i| i[:user_id] == user_id.to_i}] = obj
|
172
|
+
obj
|
171
173
|
end
|
172
|
-
def self.delete(
|
173
|
-
@data.delete_if { |i| i[:user_id] ==
|
174
|
+
def self.delete(user_id)
|
175
|
+
@data.delete_if { |i| i[:user_id] == user_id.to_i}
|
174
176
|
end
|
175
177
|
end
|
176
178
|
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require './spec/spec_helper'
|
2
|
+
|
3
|
+
describe 'Ananke - JSON Body' do
|
4
|
+
include Rack::Test::Methods
|
5
|
+
include Ananke
|
6
|
+
|
7
|
+
def app
|
8
|
+
Sinatra::Base
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should be able to parse a JSON Body in a basic POST route" do
|
12
|
+
post "/json", body={:name => 'one', :surname => 'sur_one'}.to_json
|
13
|
+
check_status(201)
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should be able to parse a JSON Body in a basic PUT route" do
|
17
|
+
put "/json/1", body={:name => 'one', :surname => 'sur_one'}.to_json
|
18
|
+
check_status(200)
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should be able to parse a JSON Body in a Custom Route" do
|
22
|
+
get "/json/custom", body={:name => 'one', :surname => 'sur_one'}.to_json
|
23
|
+
check_status(200)
|
24
|
+
end
|
25
|
+
|
26
|
+
module Repository
|
27
|
+
module Json
|
28
|
+
@data = []
|
29
|
+
def self.add(name, surname)
|
30
|
+
id = @data.empty? && 1 || @data.last[:id] + 1
|
31
|
+
obj = {:id => id, :name => name, :surname => surname}
|
32
|
+
@data << obj
|
33
|
+
obj
|
34
|
+
end
|
35
|
+
def self.edit(id, name, surname)
|
36
|
+
obj = {:id => id, :name => name, :surname => surname}
|
37
|
+
@data[@data.index{|i| i[:id] == id.to_i}] = obj
|
38
|
+
obj
|
39
|
+
end
|
40
|
+
def self.custom(name, surname)
|
41
|
+
@data[@data.index{|i| i[:name] == name && i[:surname] == surname}]
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
route :json do
|
46
|
+
id :id
|
47
|
+
required :name
|
48
|
+
required :surname
|
49
|
+
route_for :custom
|
50
|
+
end
|
51
|
+
end
|
data/spec/lib/link_to_spec.rb
CHANGED
data/spec/lib/linked_spec.rb
CHANGED
@@ -20,7 +20,7 @@ describe 'Resource' do
|
|
20
20
|
end
|
21
21
|
end
|
22
22
|
end
|
23
|
-
|
23
|
+
route :self do
|
24
24
|
id :user_id
|
25
25
|
end
|
26
26
|
|
@@ -56,11 +56,11 @@ describe 'Resource' do
|
|
56
56
|
def self.one(id) end
|
57
57
|
end
|
58
58
|
end
|
59
|
-
|
59
|
+
route :linked do
|
60
60
|
id :user_id
|
61
61
|
linked :line
|
62
62
|
end
|
63
|
-
|
63
|
+
route :line do
|
64
64
|
id :line_id
|
65
65
|
end
|
66
66
|
|
@@ -95,7 +95,7 @@ describe 'Resource' do
|
|
95
95
|
end
|
96
96
|
end
|
97
97
|
end
|
98
|
-
|
98
|
+
route :linked_fail do
|
99
99
|
id :user_id
|
100
100
|
linked :line
|
101
101
|
end
|
data/spec/lib/route_for_spec.rb
CHANGED
@@ -19,7 +19,7 @@ describe 'Resource Route-For' do
|
|
19
19
|
end
|
20
20
|
end
|
21
21
|
end
|
22
|
-
|
22
|
+
route :route_for do
|
23
23
|
id :link_id
|
24
24
|
route_for :custom
|
25
25
|
end
|
@@ -39,7 +39,7 @@ describe 'Resource Route-For' do
|
|
39
39
|
end
|
40
40
|
end
|
41
41
|
end
|
42
|
-
|
42
|
+
route :route_for do
|
43
43
|
id :link_id
|
44
44
|
route_for :multi, :post
|
45
45
|
end
|
data/spec/lib/validation_spec.rb
CHANGED
@@ -19,7 +19,7 @@ describe 'Resource' do
|
|
19
19
|
def self.add(data)end
|
20
20
|
end
|
21
21
|
end
|
22
|
-
|
22
|
+
route :basic do
|
23
23
|
id :user_id
|
24
24
|
required :username, :length => 4
|
25
25
|
end
|
@@ -49,7 +49,7 @@ describe 'Resource' do
|
|
49
49
|
def self.add(data)end
|
50
50
|
end
|
51
51
|
end
|
52
|
-
|
52
|
+
route :explicit do
|
53
53
|
id :user_id
|
54
54
|
required :email, :email
|
55
55
|
end
|
@@ -73,7 +73,7 @@ describe 'Resource' do
|
|
73
73
|
def self.add(data)end
|
74
74
|
end
|
75
75
|
end
|
76
|
-
|
76
|
+
route :added do
|
77
77
|
id :user_id
|
78
78
|
required :country, :country
|
79
79
|
end
|
metadata
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
name: ananke
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 0.1.
|
5
|
+
version: 0.1.1
|
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-
|
13
|
+
date: 2011-02-18 00:00:00 +02:00
|
14
14
|
default_executable:
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
@@ -100,23 +100,24 @@ extra_rdoc_files:
|
|
100
100
|
- README.rdoc
|
101
101
|
files:
|
102
102
|
- lib/ananke.rb
|
103
|
+
- lib/version.rb
|
103
104
|
- lib/ananke/settings.rb
|
104
|
-
- lib/ananke/helpers.rb
|
105
105
|
- lib/ananke/linking.rb
|
106
|
-
- lib/ananke/validation.rb
|
107
106
|
- lib/ananke/routing.rb
|
108
|
-
- lib/
|
109
|
-
-
|
110
|
-
- spec/call_chain.rb
|
107
|
+
- lib/ananke/validation.rb
|
108
|
+
- lib/ananke/helpers.rb
|
111
109
|
- spec/dumping.rb
|
112
110
|
- spec/cov_adapter.rb
|
113
111
|
- spec/lib/ananke_spec.rb
|
114
|
-
- spec/lib/route_for_spec.rb
|
115
|
-
- spec/lib/out_spec.rb
|
116
112
|
- spec/lib/validation_spec.rb
|
117
|
-
- spec/lib/
|
113
|
+
- spec/lib/out_spec.rb
|
114
|
+
- spec/lib/json_spec.rb
|
118
115
|
- spec/lib/link_to_spec.rb
|
116
|
+
- spec/lib/route_for_spec.rb
|
117
|
+
- spec/lib/linked_spec.rb
|
119
118
|
- spec/spec_helper.rb
|
119
|
+
- spec/call_chain.rb
|
120
|
+
- spec/nice_formatter.rb
|
120
121
|
- Gemfile
|
121
122
|
- Rakefile
|
122
123
|
- README.rdoc
|
@@ -127,7 +128,7 @@ licenses: []
|
|
127
128
|
post_install_message: |
|
128
129
|
**************************************************
|
129
130
|
|
130
|
-
Thank you for installing ananke-0.1.
|
131
|
+
Thank you for installing ananke-0.1.1
|
131
132
|
|
132
133
|
Please be sure to look at README.rdoc to see what might have changed
|
133
134
|
since the last release and how to use this GEM.
|
@@ -156,16 +157,17 @@ rubyforge_project:
|
|
156
157
|
rubygems_version: 1.5.0
|
157
158
|
signing_key:
|
158
159
|
specification_version: 3
|
159
|
-
summary: ananke-0.1.
|
160
|
+
summary: ananke-0.1.1
|
160
161
|
test_files:
|
161
|
-
- spec/nice_formatter.rb
|
162
|
-
- spec/call_chain.rb
|
163
162
|
- spec/dumping.rb
|
164
163
|
- spec/cov_adapter.rb
|
165
164
|
- spec/lib/ananke_spec.rb
|
166
|
-
- spec/lib/route_for_spec.rb
|
167
|
-
- spec/lib/out_spec.rb
|
168
165
|
- spec/lib/validation_spec.rb
|
169
|
-
- spec/lib/
|
166
|
+
- spec/lib/out_spec.rb
|
167
|
+
- spec/lib/json_spec.rb
|
170
168
|
- spec/lib/link_to_spec.rb
|
169
|
+
- spec/lib/route_for_spec.rb
|
170
|
+
- spec/lib/linked_spec.rb
|
171
171
|
- spec/spec_helper.rb
|
172
|
+
- spec/call_chain.rb
|
173
|
+
- spec/nice_formatter.rb
|