wsdsl 0.2.0 → 0.2.1
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/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: []
|