wsdsl 0.2.0 → 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +52 -1
- data/VERSION +1 -1
- data/lib/response.rb +138 -2
- data/lib/wsdsl.rb +1 -0
- data/spec/json_response_description_spec.rb +92 -0
- data/spec/wsdsl_spec.rb +2 -2
- data/wsdsl.gemspec +7 -16
- metadata +22 -35
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# Web Service DSL
|
2
2
|
|
3
|
-
WSDSL is a simple DSL
|
3
|
+
WSDSL is a simple DSL allowing developers to simply describe and
|
4
4
|
document their web APIS. For instance:
|
5
5
|
|
6
6
|
|
@@ -87,6 +87,57 @@ Or a more complex example:
|
|
87
87
|
end
|
88
88
|
|
89
89
|
|
90
|
+
## JSON APIs
|
91
|
+
|
92
|
+
This library was designed with XML responses in mind and JSON support
|
93
|
+
was added later on which explains why some response methods are aliases.
|
94
|
+
Consider the following JSON response:
|
95
|
+
|
96
|
+
{ people: [
|
97
|
+
{
|
98
|
+
id : 1,
|
99
|
+
online : false,
|
100
|
+
created_at : 123123123123,
|
101
|
+
team : {
|
102
|
+
id : 1231,
|
103
|
+
score : 123.32
|
104
|
+
}
|
105
|
+
},
|
106
|
+
{
|
107
|
+
id : 2,
|
108
|
+
online : true,
|
109
|
+
created_at : 123123123123,
|
110
|
+
team: {
|
111
|
+
id : 1233,
|
112
|
+
score : 1.32
|
113
|
+
}
|
114
|
+
},
|
115
|
+
] }
|
116
|
+
|
117
|
+
It would be described as follows:
|
118
|
+
|
119
|
+
describe_service "json_list" do |service|
|
120
|
+
service.formats :json
|
121
|
+
service.response do |response|
|
122
|
+
response.array :people do |node|
|
123
|
+
node.integer :id
|
124
|
+
node.boolean :online
|
125
|
+
node.datetime :created_at
|
126
|
+
node.object :team do |team|
|
127
|
+
team.integer :id
|
128
|
+
team.float :score
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
Nodes/elements can also use some meta attributes. Currently the
|
135
|
+
following meta attributes are available:
|
136
|
+
|
137
|
+
* key (refers to an attribute name that is key to this object)
|
138
|
+
* type (refers to the type of object described, valuable when using JSON
|
139
|
+
cross OO based apps.
|
140
|
+
|
90
141
|
## Test suite
|
91
142
|
|
92
143
|
This library comes with a test suite requiring Ruby 1.9.2
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.2.
|
1
|
+
0.2.1
|
data/lib/response.rb
CHANGED
@@ -13,6 +13,20 @@ class WSDSL
|
|
13
13
|
@elements = []
|
14
14
|
end
|
15
15
|
|
16
|
+
alias :nodes :elements
|
17
|
+
|
18
|
+
# Shortcut to automatically create a typed node.
|
19
|
+
# Very useful when describing a JSON response.
|
20
|
+
#
|
21
|
+
# @param [String, Symbol] name the name of the element.
|
22
|
+
# @param [Hash] opts the element options.
|
23
|
+
# @see Element#array
|
24
|
+
def array(name, opts={})
|
25
|
+
el = element(opts.merge(:name => name))
|
26
|
+
yield el if block_given?
|
27
|
+
el
|
28
|
+
end
|
29
|
+
|
16
30
|
# Defines a new element and yields the content of an optional block
|
17
31
|
# Each new element is then stored in the elements array.
|
18
32
|
#
|
@@ -32,6 +46,7 @@ class WSDSL
|
|
32
46
|
el = Element.new(opts[:name], opts[:type])
|
33
47
|
yield(el) if block_given?
|
34
48
|
@elements << el
|
49
|
+
el
|
35
50
|
end
|
36
51
|
|
37
52
|
# Returns a response element object based on its name
|
@@ -57,10 +72,17 @@ class WSDSL
|
|
57
72
|
# @api public
|
58
73
|
attr_reader :type
|
59
74
|
|
75
|
+
# The optional lookup key of an object
|
76
|
+
attr_reader :key
|
77
|
+
|
60
78
|
# @return [Array<WSDSL::Response::Element::Attribute>] An array of attributes
|
61
79
|
# @api public
|
62
80
|
attr_reader :attributes
|
63
81
|
|
82
|
+
# @return [Array<WSDSL::Response::Element::MetaAttribute>] An array of meta attributes
|
83
|
+
# @api public
|
84
|
+
attr_reader :meta_attributes
|
85
|
+
|
64
86
|
# @return [Array] An array of vectors/arrays
|
65
87
|
# @api public
|
66
88
|
attr_reader :vectors
|
@@ -72,6 +94,12 @@ class WSDSL
|
|
72
94
|
# @return [NilClass, Array<WSDSL::Response::Element>] The optional nested elements
|
73
95
|
attr_reader :elements
|
74
96
|
|
97
|
+
# Alias to use a JSON/JS jargon instead of XML.
|
98
|
+
alias :properties :attributes
|
99
|
+
|
100
|
+
# Alias to use a JSON/JS jargon instead of XML.
|
101
|
+
alias :objects :elements
|
102
|
+
|
75
103
|
# param [String, Symbol] name The name of the element
|
76
104
|
# param [String, Symbol] type The optional type of the element
|
77
105
|
# @api public
|
@@ -82,7 +110,9 @@ class WSDSL
|
|
82
110
|
@name = name
|
83
111
|
@type = type
|
84
112
|
@attributes = []
|
113
|
+
@meta_attributes = []
|
85
114
|
@vectors = []
|
115
|
+
@key = nil
|
86
116
|
# we don't need to initialize the nested elements, by default they should be nil
|
87
117
|
end
|
88
118
|
|
@@ -115,6 +145,29 @@ class WSDSL
|
|
115
145
|
@attributes
|
116
146
|
end
|
117
147
|
|
148
|
+
# sets a new meta attribute and returns the entire list of meta attributes
|
149
|
+
#
|
150
|
+
# @param [Hash] opts An element's attribute options
|
151
|
+
# @option opts [String, Symbol] attribute_name The name of the attribute, the value being the type
|
152
|
+
# @option opts [String, Symbol] :mock An optional mock value used by service related tools
|
153
|
+
#
|
154
|
+
# @example Creation of a response attribute called 'best_lap_time'
|
155
|
+
# service.response do |response|
|
156
|
+
# response.element(:name => "my_stats", :type => 'Leaderboard') do |e|
|
157
|
+
# e.meta_attribute "id" => :key
|
158
|
+
# end
|
159
|
+
# end
|
160
|
+
#
|
161
|
+
# @return [Array<WSDSL::Response::MetaAttribute>]
|
162
|
+
# @api public
|
163
|
+
def meta_attribute(opts)
|
164
|
+
raise ArgumentError unless opts.is_a?(Hash)
|
165
|
+
# extract the documentation part and add it where it belongs
|
166
|
+
new_attribute = MetaAttribute.new(opts)
|
167
|
+
@meta_attributes << new_attribute
|
168
|
+
@meta_attributes
|
169
|
+
end
|
170
|
+
|
118
171
|
# Defines an array aka vector of elements.
|
119
172
|
#
|
120
173
|
# @param [Hash] opts A hash representing the array information, usually a name and a type.
|
@@ -167,11 +220,88 @@ class WSDSL
|
|
167
220
|
#
|
168
221
|
# @return [Array<WSDSL::Response::Element>]
|
169
222
|
# @api public
|
170
|
-
def element(opts={})
|
223
|
+
def element(opts={}, &block)
|
171
224
|
el = Element.new(opts[:name], opts[:type])
|
172
|
-
|
225
|
+
block.call(el) if block_given?
|
173
226
|
@elements ||= []
|
174
227
|
@elements << el
|
228
|
+
el
|
229
|
+
end
|
230
|
+
|
231
|
+
# Shortcut to create a new element.
|
232
|
+
#
|
233
|
+
# @param [Symbol, String] name the name of the element.
|
234
|
+
# @param [Hash] opts the options for the newly created element.
|
235
|
+
def object(name, opts={}, &block)
|
236
|
+
element(opts.merge(:name => name), &block)
|
237
|
+
end
|
238
|
+
|
239
|
+
# Getter/setter for the key meta attribute.
|
240
|
+
# A key name can be used to lookup an object by a primary key for instance.
|
241
|
+
#
|
242
|
+
# @param [Symbol, String] name the name of the key attribute.
|
243
|
+
# @param [Hash] opts the options attached with the key.
|
244
|
+
def key(name=nil, opts={})
|
245
|
+
meta_attribute_getter_setter(:key, name, opts)
|
246
|
+
end
|
247
|
+
|
248
|
+
# Getter/setter for the type meta attribute.
|
249
|
+
#
|
250
|
+
# @param [Symbol, String] name the name of the type attribute.
|
251
|
+
# @param [Hash] opts the options attached with the key.
|
252
|
+
def type(name=nil, opts={})
|
253
|
+
meta_attribute_getter_setter(:type, name, opts)
|
254
|
+
end
|
255
|
+
|
256
|
+
# Shortcut to create a string attribute
|
257
|
+
#
|
258
|
+
# @param [Symbol, String] name the name of the attribute.
|
259
|
+
# @param [Hash] opts the attribute options.
|
260
|
+
def string(name=nil, opts={})
|
261
|
+
attribute(opts.merge(:name => name, :type => :string))
|
262
|
+
end
|
263
|
+
|
264
|
+
# Shortcut to create a string attribute
|
265
|
+
#
|
266
|
+
# @param [Symbol, String] name the name of the attribute.
|
267
|
+
# @param [Hash] opts the attribute options.
|
268
|
+
def integer(name=nil, opts={})
|
269
|
+
attribute({name => :integer}.merge(opts))
|
270
|
+
end
|
271
|
+
|
272
|
+
# Shortcut to create a string attribute
|
273
|
+
#
|
274
|
+
# @param [Symbol, String] name the name of the attribute.
|
275
|
+
# @param [Hash] opts the attribute options.
|
276
|
+
def float(name=nil, opts={})
|
277
|
+
attribute({name => :float}.merge(opts))
|
278
|
+
end
|
279
|
+
|
280
|
+
# Shortcut to create a string attribute
|
281
|
+
#
|
282
|
+
# @param [Symbol, String] name the name of the attribute.
|
283
|
+
# @param [Hash] opts the attribute options.
|
284
|
+
def boolean(name=nil, opts={})
|
285
|
+
attribute({name => :boolean}.merge(opts))
|
286
|
+
end
|
287
|
+
|
288
|
+
# Shortcut to create a string attribute
|
289
|
+
#
|
290
|
+
# @param [Symbol, String] name the name of the attribute.
|
291
|
+
# @param [Hash] opts the attribute options.
|
292
|
+
def datetime(name=nil, opts={})
|
293
|
+
attribute({name => :datetime}.merge(opts))
|
294
|
+
end
|
295
|
+
|
296
|
+
private
|
297
|
+
|
298
|
+
# Create a meta element attribute
|
299
|
+
def meta_attribute_getter_setter(type, name, opts)
|
300
|
+
if name
|
301
|
+
meta_attribute({name => type}.merge(opts))
|
302
|
+
else
|
303
|
+
meta_attributes.find{|att| att.type == type}
|
304
|
+
end
|
175
305
|
end
|
176
306
|
|
177
307
|
# Response element's attribute class
|
@@ -181,6 +311,7 @@ class WSDSL
|
|
181
311
|
# @return [String, #to_s] The attribute's name.
|
182
312
|
# @api public
|
183
313
|
attr_reader :name
|
314
|
+
alias :value :name
|
184
315
|
|
185
316
|
# @return [Symbol, String, #to_s] The attribute's type such as boolean, string etc..
|
186
317
|
# @api public
|
@@ -223,6 +354,11 @@ class WSDSL
|
|
223
354
|
end
|
224
355
|
end
|
225
356
|
|
357
|
+
# Response's meta attribute meant to set some extra
|
358
|
+
# attributes which are not part of the response per se.
|
359
|
+
class MetaAttribute < Attribute
|
360
|
+
end
|
361
|
+
|
226
362
|
# Array of objects inside an element
|
227
363
|
# @api public
|
228
364
|
class Vector
|
data/lib/wsdsl.rb
CHANGED
@@ -0,0 +1,92 @@
|
|
1
|
+
require File.expand_path("spec_helper", File.dirname(__FILE__))
|
2
|
+
|
3
|
+
describe "WSDSL JSON response description" do
|
4
|
+
|
5
|
+
# JSON response example
|
6
|
+
=begin
|
7
|
+
{ vouchers: [
|
8
|
+
{
|
9
|
+
id : 1,
|
10
|
+
redeemed : false,
|
11
|
+
created_at : 123123123123,
|
12
|
+
option: {
|
13
|
+
id : 1231,
|
14
|
+
price: 123.32
|
15
|
+
}
|
16
|
+
},
|
17
|
+
{
|
18
|
+
id : 2,
|
19
|
+
redeemed : true,
|
20
|
+
created_at : 123123123123,
|
21
|
+
option: {
|
22
|
+
id : 1233,
|
23
|
+
price: 1.32
|
24
|
+
}
|
25
|
+
},
|
26
|
+
] }
|
27
|
+
=end
|
28
|
+
|
29
|
+
before :all do
|
30
|
+
@service = describe_service "json_list" do |service|
|
31
|
+
service.formats :json
|
32
|
+
service.response do |response|
|
33
|
+
response.array :vouchers do |node|
|
34
|
+
node.key :id
|
35
|
+
node.type :Voucher
|
36
|
+
node.integer :id, :doc => "Identifier"
|
37
|
+
node.boolean :redeemed
|
38
|
+
node.datetime :created_at
|
39
|
+
node.object :option do |option|
|
40
|
+
option.integer :id
|
41
|
+
option.integer :deal_id, :mock => 1
|
42
|
+
option.float :price
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
@response = @service.response
|
48
|
+
@root_node = @response.nodes.find{|n| n.name == :vouchers}
|
49
|
+
|
50
|
+
end
|
51
|
+
|
52
|
+
it "should handle the json root node" do
|
53
|
+
@root_node.should_not be_nil
|
54
|
+
end
|
55
|
+
|
56
|
+
it "should handle a node property list" do
|
57
|
+
props = @root_node.properties
|
58
|
+
props.should_not be_empty
|
59
|
+
{:id => :integer, :redeemed => :boolean, :created_at => :datetime}.each do |key, type|
|
60
|
+
prop = props.find{|prop| prop.name == key}
|
61
|
+
prop.should_not be_nil
|
62
|
+
prop.type.should == type
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
it "should handle a nested object with properties" do
|
67
|
+
@root_node.objects.should_not be_nil
|
68
|
+
option = @root_node.objects.find{|o| o.name == :option}
|
69
|
+
option.should_not be_nil
|
70
|
+
{:id => :integer, :deal_id => :integer, :price => :float}.each do |key, type|
|
71
|
+
prop = option.properties.find{|prop| prop.name == key}
|
72
|
+
if prop.nil?
|
73
|
+
puts option.properties.inspect
|
74
|
+
puts [key, type].inspect
|
75
|
+
end
|
76
|
+
prop.should_not be_nil
|
77
|
+
prop.type.should == type
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
it "should allow some meta attributes" do
|
82
|
+
atts = @root_node.meta_attributes
|
83
|
+
atts.should_not be_nil
|
84
|
+
{:key => :id, :type => :Voucher}.each do |type, value|
|
85
|
+
meta = atts.find{|att| att.type == type}
|
86
|
+
puts [type, atts].inspect if meta.nil?
|
87
|
+
meta.should_not be_nil
|
88
|
+
meta.value.should == value
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
end
|
data/spec/wsdsl_spec.rb
CHANGED
@@ -60,8 +60,8 @@ describe WSDSL do
|
|
60
60
|
end
|
61
61
|
|
62
62
|
it "should have a default action" do
|
63
|
-
|
64
|
-
|
63
|
+
service = WSDSL.new('spec_test.xml')
|
64
|
+
service.action.should == 'list'
|
65
65
|
end
|
66
66
|
|
67
67
|
it "should route to show when an id is the last passed param" do
|
data/wsdsl.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{wsdsl}
|
8
|
-
s.version = "0.2.
|
8
|
+
s.version = "0.2.1"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
-
s.authors = [
|
12
|
-
s.date = %q{2011-
|
11
|
+
s.authors = [%q{Matt Aimonetti}]
|
12
|
+
s.date = %q{2011-09-02}
|
13
13
|
s.description = %q{A Ruby DSL describing Web Services without implementation details.}
|
14
14
|
s.email = %q{mattaimonetti@gmail.com}
|
15
15
|
s.extra_rdoc_files = [
|
@@ -32,6 +32,7 @@ Gem::Specification.new do |s|
|
|
32
32
|
"lib/wsdsl.rb",
|
33
33
|
"spec/hello_world_controller.rb",
|
34
34
|
"spec/hello_world_service.rb",
|
35
|
+
"spec/json_response_description_spec.rb",
|
35
36
|
"spec/params_verification_spec.rb",
|
36
37
|
"spec/preferences_service.rb",
|
37
38
|
"spec/spec_helper.rb",
|
@@ -41,20 +42,10 @@ Gem::Specification.new do |s|
|
|
41
42
|
"wsdsl.gemspec"
|
42
43
|
]
|
43
44
|
s.homepage = %q{http://github.com/mattetti/wsdsl}
|
44
|
-
s.licenses = [
|
45
|
-
s.require_paths = [
|
46
|
-
s.rubygems_version = %q{1.
|
45
|
+
s.licenses = [%q{MIT}]
|
46
|
+
s.require_paths = [%q{lib}]
|
47
|
+
s.rubygems_version = %q{1.8.6}
|
47
48
|
s.summary = %q{Web Service DSL}
|
48
|
-
s.test_files = [
|
49
|
-
"spec/hello_world_controller.rb",
|
50
|
-
"spec/hello_world_service.rb",
|
51
|
-
"spec/params_verification_spec.rb",
|
52
|
-
"spec/preferences_service.rb",
|
53
|
-
"spec/spec_helper.rb",
|
54
|
-
"spec/test_services.rb",
|
55
|
-
"spec/wsdsl_sinatra_ext_spec.rb",
|
56
|
-
"spec/wsdsl_spec.rb"
|
57
|
-
]
|
58
49
|
|
59
50
|
if s.respond_to? :specification_version then
|
60
51
|
s.specification_version = 3
|
metadata
CHANGED
@@ -1,28 +1,24 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: wsdsl
|
3
|
-
version: !ruby/object:Gem::Version
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.2.1
|
4
5
|
prerelease:
|
5
|
-
version: 0.2.0
|
6
6
|
platform: ruby
|
7
|
-
authors:
|
7
|
+
authors:
|
8
8
|
- Matt Aimonetti
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
|
13
|
-
date: 2011-05-19 00:00:00 Z
|
12
|
+
date: 2011-09-02 00:00:00.000000000Z
|
14
13
|
dependencies: []
|
15
|
-
|
16
14
|
description: A Ruby DSL describing Web Services without implementation details.
|
17
15
|
email: mattaimonetti@gmail.com
|
18
16
|
executables: []
|
19
|
-
|
20
17
|
extensions: []
|
21
|
-
|
22
|
-
extra_rdoc_files:
|
18
|
+
extra_rdoc_files:
|
23
19
|
- LICENSE
|
24
20
|
- README.md
|
25
|
-
files:
|
21
|
+
files:
|
26
22
|
- LICENSE
|
27
23
|
- README.md
|
28
24
|
- Rakefile
|
@@ -38,6 +34,7 @@ files:
|
|
38
34
|
- lib/wsdsl.rb
|
39
35
|
- spec/hello_world_controller.rb
|
40
36
|
- spec/hello_world_service.rb
|
37
|
+
- spec/json_response_description_spec.rb
|
41
38
|
- spec/params_verification_spec.rb
|
42
39
|
- spec/preferences_service.rb
|
43
40
|
- spec/spec_helper.rb
|
@@ -46,38 +43,28 @@ files:
|
|
46
43
|
- spec/wsdsl_spec.rb
|
47
44
|
- wsdsl.gemspec
|
48
45
|
homepage: http://github.com/mattetti/wsdsl
|
49
|
-
licenses:
|
46
|
+
licenses:
|
50
47
|
- MIT
|
51
48
|
post_install_message:
|
52
49
|
rdoc_options: []
|
53
|
-
|
54
|
-
require_paths:
|
50
|
+
require_paths:
|
55
51
|
- lib
|
56
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
52
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
57
53
|
none: false
|
58
|
-
requirements:
|
59
|
-
- -
|
60
|
-
- !ruby/object:Gem::Version
|
61
|
-
version:
|
62
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
54
|
+
requirements:
|
55
|
+
- - ! '>='
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: '0'
|
58
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
63
59
|
none: false
|
64
|
-
requirements:
|
65
|
-
- -
|
66
|
-
- !ruby/object:Gem::Version
|
67
|
-
version:
|
60
|
+
requirements:
|
61
|
+
- - ! '>='
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: '0'
|
68
64
|
requirements: []
|
69
|
-
|
70
65
|
rubyforge_project:
|
71
|
-
rubygems_version: 1.
|
66
|
+
rubygems_version: 1.8.6
|
72
67
|
signing_key:
|
73
68
|
specification_version: 3
|
74
69
|
summary: Web Service DSL
|
75
|
-
test_files:
|
76
|
-
- spec/hello_world_controller.rb
|
77
|
-
- spec/hello_world_service.rb
|
78
|
-
- spec/params_verification_spec.rb
|
79
|
-
- spec/preferences_service.rb
|
80
|
-
- spec/spec_helper.rb
|
81
|
-
- spec/test_services.rb
|
82
|
-
- spec/wsdsl_sinatra_ext_spec.rb
|
83
|
-
- spec/wsdsl_spec.rb
|
70
|
+
test_files: []
|