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 CHANGED
@@ -1,6 +1,6 @@
1
1
  # Web Service DSL
2
2
 
3
- WSDSL is a simple DSL allowind developers to simply describe and
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.0
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
- yield(el) if block_given?
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
@@ -354,6 +354,7 @@ module Kernel
354
354
  service = WSDSL.new(url)
355
355
  yield service
356
356
  WSList.add(service)
357
+ service
357
358
  end
358
359
 
359
360
  end
@@ -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
- service = WSDSL.new('spec_test.xml')
64
- service.action.should == 'list'
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.0"
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 = ["Matt Aimonetti"]
12
- s.date = %q{2011-05-19}
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 = ["MIT"]
45
- s.require_paths = ["lib"]
46
- s.rubygems_version = %q{1.7.2}
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: "0"
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: "0"
60
+ requirements:
61
+ - - ! '>='
62
+ - !ruby/object:Gem::Version
63
+ version: '0'
68
64
  requirements: []
69
-
70
65
  rubyforge_project:
71
- rubygems_version: 1.7.2
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: []