weasel_diesel 1.2.2 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 76695321f4c49f270788ffc3743ed2ca1668c774
4
- data.tar.gz: 567a24d4bac5544bb3d7d89df0fea271afa273b0
3
+ metadata.gz: 66a37bea5e3454ee526eb9281ae4e98ce75945db
4
+ data.tar.gz: 29e993efacc6873959b347b4141e93f1cbb85738
5
5
  SHA512:
6
- metadata.gz: 9fc1388dc4e52f7ec91b518f26319d85e4b14f92bf586f036cc53e920ee9017cbffeda361b4b0c786aa06d5fde37f79ba01df0fabbc2ae4e68c4be4688277377
7
- data.tar.gz: be2eb8217e849bb8b4bdd9b2fe818d4c1ca7928750da35271f707f797636ec8a18722e51c2c83962e10660cb55c45aa6ef7603fa443d89488024c77875af0af5
6
+ metadata.gz: a04322e780856bf69f40e3311cfd3fdd00c4bbabb492b30b8822e99537dac179a7d1929040c3710313df8aa753803415a5465387fe58789a3287f3187477f31d
7
+ data.tar.gz: 473aa3828ff0474ecafad534d986353d67b415fbdcbb9b358ddc461146538ae396e4523882db54ef9705954dd2c605c40db7385976c9ac3ca9235b417eb96e16
@@ -1,6 +1,5 @@
1
1
  language: ruby
2
2
  rvm:
3
- - 1.8.7
4
3
  - 1.9.3
5
4
  - 2.0.0
6
5
  - jruby
@@ -3,10 +3,16 @@
3
3
  All changes can be seen on GitHub and git tags are used to isolate each
4
4
  release.
5
5
 
6
- 1.2.2:
6
+ ## 1.3.0
7
+ * Move documentation generation from wd_sinatra into Weasel-Diesel.
8
+ * Drop support for Ruby 1.8.7.
9
+ * Fix rspec deprecation: `expect { }.not_to raise_error(SpecificErrorClass)`
10
+ * DSL now only extends the top level main object.
11
+
12
+ ## 1.2.2:
7
13
  * Added support for anonymous top level arrays.
8
14
 
9
- *1.2.1*:
15
+ ## 1.2.1:
10
16
 
11
17
  * Modified the way an empty string param is cast/verified. If a param is
12
18
  passed as an empty string but the param isn't specified as a string, the
@@ -15,8 +21,7 @@ an integer param, the cast params will look like that: `{'id' => nil}`,
15
21
  however if `name` is a string param and `{'name' => ''}` is passed, the
16
22
  value won't be nullified.
17
23
 
18
-
19
- **1.2.0**:
24
+ ## 1.2.0:
20
25
 
21
26
  * All service urls are now stored with a prepended slash (if not defined
22
27
  with one). `WDList.find(<verb>, <url>)` will automatically find the
data/Gemfile CHANGED
@@ -1,4 +1,4 @@
1
- source "http://rubygems.org"
1
+ source "https://rubygems.org"
2
2
 
3
3
  # Specify your gem's dependencies in weasel_diesel.gemspec
4
4
  gemspec
data/LICENSE CHANGED
@@ -1,4 +1,6 @@
1
- Copyright (c) 2012 Matt Aimonetti
1
+ MIT: http://mattaimonetti.mit-license.org
2
+
3
+ Copyright (c) 2013 Matt Aimonetti
2
4
 
3
5
  Permission is hereby granted, free of charge, to any person obtaining
4
6
  a copy of this software and associated documentation files (the
data/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  [![CI Build Status](https://secure.travis-ci.org/mattetti/Weasel-Diesel.png?branch=master)](http://travis-ci.org/mattetti/Weasel-Diesel)
4
4
 
5
- Weasel Diesel is a DSL to describe and document your web API.
5
+ Weasel Diesel is a DSL to describe and document your web API.
6
6
 
7
7
  To get you going quickly, see the [generator for sinatra apps](https://github.com/mattetti/wd-sinatra).
8
8
  The wd_sinatra gem allows you to generate the structure for a sinatra app using Weasel Diesel and with lots of goodies.
@@ -34,8 +34,8 @@ describe_service "/hello_world" do |service|
34
34
 
35
35
  # DOCUMENTATION
36
36
  service.documentation do |doc|
37
- doc.overall "This service provides a simple hello world implementation example."
38
- doc.example "<code>curl -I 'http://localhost:9292/hello_world?name=Matt'</code>"
37
+ doc.overall "This service provides a simple hello world implementation example."
38
+ doc.example "<code>curl -I 'http://localhost:9292/hello_world?name=Matt'</code>"
39
39
  end
40
40
 
41
41
  # ACTION/IMPLEMENTATION (specific to the sinatra app example, can
@@ -55,34 +55,34 @@ Or a more complex example using XML:
55
55
  describe_service "/wsdsl/test.xml" do |service|
56
56
  service.formats :xml, :json
57
57
  service.http_verb :get
58
-
58
+
59
59
  # INPUT
60
60
  service.params do |p|
61
61
  p.string :framework, :in => SpecOptions, :null => false, :required => true
62
-
63
- p.datetime :timestamp,
64
- :default => Time.now,
62
+
63
+ p.datetime :timestamp,
64
+ :default => Time.now,
65
65
  :doc => "The test framework used, could be one of the two following: #{SpecOptions.join(", ")}."
66
66
 
67
67
  p.string :alpha, :in => ['a', 'b', 'c']
68
- p.string :version,
68
+ p.string :version,
69
69
  :null => false,
70
70
  :doc => "The version of the framework to use."
71
-
71
+
72
72
  p.integer :num, :minvalue => 42
73
73
  p.namespace :user do |user|
74
74
  user.integer :id, :required => :true
75
75
  end
76
76
  end
77
-
77
+
78
78
  # OUTPUT
79
- # the response contains a list of player creation ratings each object in the list
79
+ # the response contains a list of player creation ratings each object in the list
80
80
  service.response do |response|
81
81
  response.element(:name => "player_creation_ratings") do |e|
82
82
  e.attribute :id => :integer, :doc => "id doc"
83
83
  e.attribute :is_accepted => :boolean, :doc => "is accepted doc"
84
84
  e.attribute :name => :string, :doc => "name doc"
85
-
85
+
86
86
  e.array :name => 'player_creation_rating', :type => 'PlayerCreationRating' do |a|
87
87
  a.attribute :comments => :string, :doc => "comments doc"
88
88
  a.attribute :player_id => :integer, :doc => "player_id doc"
@@ -91,14 +91,14 @@ Or a more complex example using XML:
91
91
  end
92
92
  end
93
93
  end
94
-
94
+
95
95
  # DOCUMENTATION
96
96
  service.documentation do |doc|
97
97
  # doc.overall <markdown description text>
98
98
  doc.overall <<-DOC
99
99
  This is a test service used to test the framework.
100
100
  DOC
101
-
101
+
102
102
  # doc.example <markdown text>
103
103
  doc.example <<-DOC
104
104
  The most common way to use this service looks like that:
@@ -178,7 +178,7 @@ This is particuliarly frequent when using Rails for instance.
178
178
 
179
179
  ```ruby
180
180
  service.params do |param|
181
- param.string :framework,
181
+ param.string :framework,
182
182
  :in => ['RSpec', 'Bacon'],
183
183
  :required => true,
184
184
  :doc => "The test framework used, could be one of the two following: #{WeaselDieselSpecOptions.join(", ")}."
@@ -240,26 +240,26 @@ end
240
240
 
241
241
  Consider the following JSON response:
242
242
 
243
- ```
244
- { people: [
245
- {
246
- id : 1,
243
+ ```
244
+ { people: [
245
+ {
246
+ id : 1,
247
247
  online : false,
248
- created_at : 123123123123,
248
+ created_at : 123123123123,
249
249
  team : {
250
250
  id : 1231,
251
251
  score : 123.32
252
252
  }
253
- },
254
- {
255
- id : 2,
253
+ },
254
+ {
255
+ id : 2,
256
256
  online : true,
257
- created_at : 123123123123,
257
+ created_at : 123123123123,
258
258
  team: {
259
259
  id : 1233,
260
260
  score : 1.32
261
261
  }
262
- },
262
+ },
263
263
  ] }
264
264
  ```
265
265
 
@@ -287,7 +287,7 @@ Nodes/elements can also use some meta-attributes including:
287
287
  * `key` : refers to an attribute name that is key to this object
288
288
  * `type` : refers to the type of object described, valuable when using JSON across OO based apps.
289
289
 
290
- JSON response validation can be done using an optional module as shown in
290
+ JSON response validation can be done using an optional module as shown in
291
291
  (spec/json_response_verification_spec.rb)[https://github.com/mattetti/Weasel-Diesel/blob/master/spec/json_response_verification_spec.rb].
292
292
  The goal of this module is to help automate API testing by
293
293
  validating the data structure of the returned object.
@@ -312,7 +312,7 @@ end
312
312
  ```
313
313
 
314
314
  Actual output:
315
- ```
315
+ ```
316
316
  {"name": "Example"}
317
317
  ```
318
318
 
@@ -328,42 +328,20 @@ describe_service "example" do |service|
328
328
  end
329
329
  ```
330
330
 
331
+ ## Documentation generation
331
332
 
332
- ## Test Suite & Dependencies
333
-
334
- The test suite requires Ruby 1.9.* along with `RSpec`, `Rack`, and `Sinatra` gems.
335
-
336
- ## Usage with Ruby 1.8
337
-
338
- This library prioritizes Ruby 1.9, but 1.8 support was added
339
- via the backports library and some tweaks.
340
-
341
- However, because Ruby 1.8 hashes do not preserve insert order, the following syntax
342
- **will not work**:
343
-
344
- ``` ruby
345
- service.response do |response|
346
- response.element(:name => "player_creation_ratings") do |e|
347
- e.attribute :id => :integer, :doc => "id doc"
348
- e.attribute :is_accepted => :boolean, :doc => "is accepted doc"
349
- e.attribute :name => :string, :doc => "name doc"
350
- end
351
- end
333
+ ```bash
334
+ $ weasel_diesel generate_doc <SOURCE_PATH> <DESTINATION_PATH>
352
335
  ```
353
336
 
354
- Instead, this alternate syntax must be used:
337
+ To generate documentation for the APIs you created in the api folder. The
338
+ source path is the location of your ruby files. The destination is optional,
339
+ 'doc' is the default.
355
340
 
356
- ``` ruby
357
- service.response do |response|
358
- response.element(:name => "player_creation_ratings") do |e|
359
- e.integer :id, :doc => "id doc"
360
- e.boolean :is_accepted, :doc => "is accepted doc"
361
- e.string :name, :doc => "name doc"
362
- end
363
- end
364
- ```
365
341
 
366
- The end results are identical.
342
+ ## Test Suite & Dependencies
343
+
344
+ The test suite requires `rspec`, `rack`, and `sinatra` gems.
367
345
 
368
346
  ## Copyright
369
347
 
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+ require "rubygems"
3
+ require_relative "../lib/weasel_diesel/cli"
4
+
5
+ WeaselDiesel::CLI.start
@@ -1,5 +1,5 @@
1
1
  require 'forwardable'
2
- require File.expand_path('./../params_verification', File.dirname(__FILE__))
2
+ require_relative '../params_verification'
3
3
 
4
4
  # Base code shared by all service controllers
5
5
  # This allows us to share code between controllers
@@ -10,44 +10,44 @@ require File.expand_path('./../params_verification', File.dirname(__FILE__))
10
10
  # @author Matt Aimonetti
11
11
  class SinatraServiceController
12
12
  extend Forwardable
13
-
13
+
14
14
  # The service controller might be loaded outside of a Sinatra App
15
15
  # in this case, we don't need to load the helpers
16
16
  if Object.const_defined?(:Sinatra)
17
- include Sinatra::Helpers
17
+ include Sinatra::Helpers
18
18
  end
19
-
19
+
20
20
  class AuthenticationFailed < StandardError; end
21
-
21
+
22
22
  # @return [WeaselDiesel] The service served by this controller
23
23
  # @api public
24
24
  attr_reader :service
25
-
25
+
26
26
  # @return [Sinatra::Application]
27
27
  # @api public
28
28
  attr_reader :app
29
-
29
+
30
30
  # @return [Hash]
31
31
  # @api public
32
32
  attr_reader :env
33
-
33
+
34
34
  # @return [Sinatra::Request]
35
35
  # @see http://rubydoc.info/github/sinatra/sinatra/Sinatra/Request
36
36
  # @api public
37
37
  attr_reader :request
38
-
38
+
39
39
  # @return [Sinatra::Response]
40
40
  # @see http://rubydoc.info/github/sinatra/sinatra/Sinatra/Response
41
41
  # @api public
42
42
  attr_reader :response
43
-
43
+
44
44
  # @return [Hash]
45
45
  # @api public
46
46
  attr_accessor :params
47
-
47
+
48
48
  # @param [Sinatra::Application] app The Sinatra app used as a reference and to access request params
49
49
  # @param [WeaselDiesel] service The service served by this controller
50
- # @raise [ParamError, NoParamsDefined, MissingParam, UnexpectedParam, InvalidParamType, InvalidParamValue]
50
+ # @raise [ParamError, NoParamsDefined, MissingParam, UnexpectedParam, InvalidParamType, InvalidParamValue]
51
51
  # If the params don't validate one of the {ParamsVerification} errors will be raised.
52
52
  # @api public
53
53
  def initialize(app, service)
@@ -56,10 +56,10 @@ class SinatraServiceController
56
56
  @request = app.request
57
57
  @response = app.response
58
58
  @service = service
59
-
59
+
60
60
  # raises an exception if the params are not valid
61
- # otherwise update the app params with potentially new params (using default values)
62
- # note that if a type if mentioned for a params, the object will be cast to this object type
61
+ # otherwise update the app params with potentially new params (using default values)
62
+ # note that if a type if mentioned for a params, the object will be cast to this object type
63
63
  @params = app.params = ParamsVerification.validate!(app.params, service.defined_params)
64
64
 
65
65
  # Authentication check
@@ -67,7 +67,7 @@ class SinatraServiceController
67
67
  raise AuthenticationFailed unless logged_in?
68
68
  end
69
69
  end
70
-
70
+
71
71
 
72
72
  # Forwarding some methods to the underlying app object
73
73
  def_delegators :app, :settings, :halt, :compile_template, :session
@@ -76,5 +76,5 @@ class SinatraServiceController
76
76
  def logged_in?
77
77
  !session[:player_id].nil?
78
78
  end
79
-
79
+
80
80
  end
@@ -24,7 +24,7 @@ class WeaselDiesel
24
24
  # Lists all top level simple elements and array elements.
25
25
  #
26
26
  # @return [Array<WeaselDiesel::Response::Element, WeaselDiesel::Response::Array>]
27
- def nodes
27
+ def nodes
28
28
  elements + arrays
29
29
  end
30
30
 
@@ -153,6 +153,7 @@ class WeaselDiesel
153
153
  @type = type
154
154
  @attributes = []
155
155
  @meta_attributes = []
156
+ @elements = []
156
157
  @vectors = []
157
158
  @key = nil
158
159
  # we don't need to initialize the nested elements, by default they should be nil
@@ -164,7 +165,7 @@ class WeaselDiesel
164
165
  # @option opts [String, Symbol] attribute_name The name of the attribute, the value being the type
165
166
  # @option opts [String, Symbol] :doc The attribute documentation
166
167
  # @option opts [String, Symbol] :mock An optional mock value used by service related tools
167
- #
168
+ #
168
169
  # @example Creation of a response attribute called 'best_lap_time'
169
170
  # service.response do |response|
170
171
  # response.element(:name => "my_stats", :type => 'Leaderboard') do |e|
@@ -174,13 +175,13 @@ class WeaselDiesel
174
175
  #
175
176
  # @return [Array<WeaselDiesel::Response::Attribute>]
176
177
  # @api public
177
- def attribute(opts, extra_opts={})
178
- raise ArgumentError unless opts.is_a?(Hash) && extra_opts.is_a?(Hash)
179
- new_attribute = Attribute.new(opts, extra_opts)
178
+ def attribute(opts)
179
+ raise ArgumentError unless opts.is_a?(Hash)
180
+ new_attribute = Attribute.new(opts)
180
181
  @attributes << new_attribute
181
182
  # document the attribute if description available
182
183
  # we might want to have a placeholder message when a response attribute isn't defined
183
- if opts.merge!(extra_opts).has_key?(:doc)
184
+ if opts.has_key?(:doc)
184
185
  @doc.attribute(new_attribute.name, opts[:doc])
185
186
  end
186
187
  @attributes
@@ -191,7 +192,7 @@ class WeaselDiesel
191
192
  # @param [Hash] opts An element's attribute options
192
193
  # @option opts [String, Symbol] attribute_name The name of the attribute, the value being the type
193
194
  # @option opts [String, Symbol] :mock An optional mock value used by service related tools
194
- #
195
+ #
195
196
  # @example Creation of a response attribute called 'best_lap_time'
196
197
  # service.response do |response|
197
198
  # response.element(:name => "my_stats", :type => 'Leaderboard') do |e|
@@ -212,12 +213,12 @@ class WeaselDiesel
212
213
  # Defines an array aka vector of elements.
213
214
  #
214
215
  # @param [String, Symbol] name The name of the array element.
215
- # @param [String, Symbol] type Optional type information, useful to store the represented
216
+ # @param [String, Symbol] type Optional type information, useful to store the represented
216
217
  # object types for instance.
217
218
  #
218
219
  # @param [Proc] &block
219
220
  # A block to execute against the newly created array.
220
- #
221
+ #
221
222
  # @example Defining an element array called 'player_creation_rating'
222
223
  # element.array 'player_creation_rating', 'PlayerCreationRating' do |a|
223
224
  # a.attribute :comments => :string
@@ -227,7 +228,7 @@ class WeaselDiesel
227
228
  # end
228
229
  # @yield [Vector] the newly created array/vector instance
229
230
  # @see Element#initialize
230
- #
231
+ #
231
232
  # @return [Array<WeaselDiesel::Response::Vector>]
232
233
  # @api public
233
234
  def array(name, type=nil)
@@ -299,7 +300,7 @@ class WeaselDiesel
299
300
  # @param [Symbol, String] name the name of the attribute.
300
301
  # @param [Hash] opts the attribute options.
301
302
  def string(name=nil, opts={})
302
- attribute({name => :string}, opts)
303
+ attribute({name => :string}.merge(opts))
303
304
  end
304
305
 
305
306
  # Shortcut to create a string attribute
@@ -307,7 +308,7 @@ class WeaselDiesel
307
308
  # @param [Symbol, String] name the name of the attribute.
308
309
  # @param [Hash] opts the attribute options.
309
310
  def integer(name=nil, opts={})
310
- attribute({name => :integer}, opts)
311
+ attribute({name => :integer}.merge(opts))
311
312
  end
312
313
 
313
314
  # Shortcut to create a string attribute
@@ -315,7 +316,7 @@ class WeaselDiesel
315
316
  # @param [Symbol, String] name the name of the attribute.
316
317
  # @param [Hash] opts the attribute options.
317
318
  def float(name=nil, opts={})
318
- attribute({name => :float}, opts)
319
+ attribute({name => :float}.merge(opts))
319
320
  end
320
321
 
321
322
  # Shortcut to create a string attribute
@@ -323,7 +324,7 @@ class WeaselDiesel
323
324
  # @param [Symbol, String] name the name of the attribute.
324
325
  # @param [Hash] opts the attribute options.
325
326
  def boolean(name=nil, opts={})
326
- attribute({name => :boolean}, opts)
327
+ attribute({name => :boolean}.merge(opts))
327
328
  end
328
329
 
329
330
  # Shortcut to create a string attribute
@@ -331,20 +332,21 @@ class WeaselDiesel
331
332
  # @param [Symbol, String] name the name of the attribute.
332
333
  # @param [Hash] opts the attribute options.
333
334
  def datetime(name=nil, opts={})
334
- attribute({name => :datetime}, opts)
335
+ attribute({name => :datetime}.merge(opts))
335
336
  end
336
337
 
337
338
  # Converts an element into a hash representation
338
339
  #
340
+ # @param [Boolean] root_node true if this node has no parents.
339
341
  # @return [Hash] the element attributes formated in a hash
340
- def to_hash
342
+ def to_hash(root_node=true)
341
343
  attrs = {}
342
344
  attributes.each{ |attr| attrs[attr.name] = attr.type }
343
- elements.each{ |el| attrs[el.name] = el.to_hash } if elements
345
+ (vectors + elements).each{ |el| attrs[el.name] = el.to_hash(false) }
344
346
  if self.class == Vector
345
- name ? {name => [attrs]} : [attrs]
347
+ (root_node && name) ? {name => [attrs]} : [attrs]
346
348
  else
347
- name ? {name => attrs} : attrs
349
+ (root_node && name) ? {name => attrs} : attrs
348
350
  end
349
351
  end
350
352
 
@@ -429,17 +431,14 @@ class WeaselDiesel
429
431
  # name, type, doc, type
430
432
  #
431
433
  # @param [Hash, Array] o_params
432
- # @param [Hash] o_extra_params A hash with extra params passed, needed to support Ruby 1.8 :(
433
434
  #
434
435
  # @api public
435
- def initialize(o_params, o_extra_params={})
436
+ def initialize(o_params)
436
437
  params = o_params.dup
437
- extra_params = o_extra_params.dup
438
438
  if params.is_a?(Hash)
439
439
  @name, @type = params.shift
440
440
  @doc = params.delete(:doc) if params.has_key?(:doc)
441
- @doc ||= extra_params.delete(:doc) if extra_params.has_key?(:doc)
442
- @opts = params.merge!(extra_params)
441
+ @opts = params
443
442
  elsif params.is_a?(Array)
444
443
  @name = params.shift
445
444
  @type = params.shift
@@ -1,9 +1,9 @@
1
- require File.expand_path('inflection', File.dirname(__FILE__))
2
- require File.expand_path('params', File.dirname(__FILE__))
3
- require File.expand_path('response', File.dirname(__FILE__))
4
- require File.expand_path('documentation', File.dirname(__FILE__))
5
- require File.expand_path('ws_list', File.dirname(__FILE__))
6
- require File.expand_path('kernel_ext', File.dirname(__FILE__))
1
+ require_relative 'inflection'
2
+ require_relative 'params'
3
+ require_relative 'response'
4
+ require_relative 'documentation'
5
+ require_relative 'ws_list'
6
+ require 'weasel_diesel/dsl'
7
7
 
8
8
  # WeaselDiesel offers a web service DSL to define web services,
9
9
  # their params, http verbs, formats expected as well as the documentation
@@ -386,6 +386,12 @@ class WeaselDiesel
386
386
  end
387
387
  end
388
388
 
389
+ # Left for generators to implement. It's empty because WD itself isn't concerned
390
+ # with implementation, but needs it defined so doc generation can read WD web
391
+ # service definitions.
392
+ def implementation(&block)
393
+ end
394
+
389
395
  SERVICE_ROOT_REGEXP = /(.*?)[\/\(\.]/
390
396
  SERVICE_ACTION_REGEXP = /[\/\(\.]([a-z0-9_]+)[\/\(\.\?]/i
391
397
  SERVICE_RESTFUL_SHOW_REGEXP = /\/:[a-z0-9_]+\.\w{3}$/
@@ -422,6 +428,4 @@ class WeaselDiesel
422
428
  end
423
429
  end
424
430
 
425
-
426
-
427
431
  end
@@ -0,0 +1,60 @@
1
+ require "thor"
2
+ require_relative "../weasel_diesel"
3
+
4
+ class WeaselDiesel
5
+ class CLI < Thor
6
+ include Thor::Actions
7
+ namespace :weasel_diesel
8
+
9
+ desc "generate_doc SOURCE_PATH DESTINATION_PATH", "Generate HTML documentation for WeaselDiesel web services"
10
+ def generate_doc(source_path, destination_path="doc")
11
+ api_files = Dir.glob(File.join(destination_root, source_path, "**", "*.rb"))
12
+ if api_files.empty?
13
+ puts "No ruby files in source_path: #{File.join(destination_root, source_path)}"
14
+ return
15
+ end
16
+ api_files.each do |api|
17
+ require api
18
+ end
19
+
20
+ require 'fileutils'
21
+ destination = File.join(destination_root, destination_path)
22
+ FileUtils.mkdir_p(destination) unless File.exist?(destination)
23
+ File.open("#{destination}/index.html", "w"){|f| f << doc_template.result(binding)}
24
+ puts "Documentation available there: #{destination}/index.html"
25
+ `open #{destination}/index.html` if RUBY_PLATFORM =~ /darwin/ && !ENV['DONT_OPEN']
26
+ end
27
+
28
+ private
29
+
30
+ def response_element_html(el)
31
+ response_element_template.result(binding)
32
+ end
33
+
34
+ def input_params_html(required, optional)
35
+ input_params_template.result(binding)
36
+ end
37
+
38
+ def input_params_template
39
+ file = resources.join '_input_params.erb'
40
+ ERB.new File.read(file)
41
+ end
42
+
43
+ def response_element_template
44
+ file = resources.join '_response_element.erb'
45
+ ERB.new File.read(file)
46
+ end
47
+
48
+ def doc_template
49
+ file = resources.join 'template.erb'
50
+ ERB.new File.read(file)
51
+ end
52
+
53
+ def resources
54
+ require 'pathname'
55
+ @resources ||= Pathname.new(File.join(File.dirname(__FILE__), 'doc_generator'))
56
+ end
57
+
58
+ end
59
+
60
+ end
@@ -0,0 +1,36 @@
1
+ <table class="table table-striped table-responsive">
2
+ <tdbody>
3
+ <% [["required", required], ["optional", optional]].each do |label, rules| %>
4
+ <% unless rules.empty? %>
5
+ <% rules.each do |rule| %>
6
+ <tr>
7
+ <td>
8
+ <strong><%= rule.name %></strong>
9
+ <br />
10
+ <em><%= label %></em>
11
+ </td>
12
+ <td>
13
+ <p>
14
+ <strong><%= rule.options[:type] || 'string' %></strong>
15
+
16
+ <% if desc = rule.doc %>
17
+ - <%= desc %>
18
+ <% end %>
19
+ </p>
20
+
21
+ <% if options = rule.options[:options] %>
22
+ <strong>Options:</strong> <%= options.join(', ') %>
23
+ <br />
24
+ <% end %>
25
+
26
+ <% if default = rule.options[:default] %>
27
+ <strong>Default:</strong> <%= default %>
28
+ <br />
29
+ <% end %>
30
+ </td>
31
+ </tr>
32
+ <% end %>
33
+ <% end %>
34
+ <% end %>
35
+ </tdbody>
36
+ </table>
@@ -0,0 +1,49 @@
1
+ <table class="table table-striped table-responsive">
2
+ <tdbody>
3
+ <% if el.name %>
4
+ <tr>
5
+ <td colspan="2">
6
+ <strong><%= el.name %></strong>
7
+ <% if false && el.is_a?(WeaselDiesel::Response::Vector) %>
8
+ <span class="response-array">(Array, these are the properties of each array item)</span>
9
+ <% end %>
10
+ </td>
11
+ </tr>
12
+ <% end %>
13
+ <% el.properties.each do |prop| %>
14
+ <tr>
15
+ <td>
16
+ <strong><%= prop.name %></strong>
17
+ <br />
18
+ <em>
19
+ <% if false && prop.opts && prop.opts.respond_to?(:[]) && prop.opts[:null] %>
20
+ required
21
+ <% else %>
22
+ optional
23
+ <% end %>
24
+ </em>
25
+ </td>
26
+ <td>
27
+ <p>
28
+ <strong><%= prop.type %></strong>
29
+ <% unless true && prop.doc.nil? or prop.doc.empty? %>
30
+ - <%= prop.doc %>
31
+ <% end %>
32
+ </p>
33
+ </td>
34
+ </tr>
35
+ <% end %>
36
+
37
+ <% if false && el.arrays %>
38
+ <% el.arrays.each do |e| %>
39
+ <%= response_element_html(e) %>
40
+ <% end %>
41
+ <% end %>
42
+
43
+ <% if false && el.elements %>
44
+ <% el.elements.each do |e| %>
45
+ <%= response_element_html(e) %>
46
+ <% end %>
47
+ <% end %>
48
+ </tdbody>
49
+ </table>
@@ -0,0 +1,120 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>API Documentation</title>
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <!-- Bootstrap -->
7
+ <link rel="stylesheet" href="https://netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css">
8
+ <!-- Optional theme -->
9
+ <link rel="stylesheet" href="https://netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap-theme.min.css">
10
+
11
+ <!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries -->
12
+ <!--[if lt IE 9]>
13
+ <script src="../../assets/js/html5shiv.js"></script>
14
+ <script src="../../assets/js/respond.min.js"></script>
15
+ <![endif]-->
16
+ </head>
17
+ <body>
18
+ <div class="container">
19
+ <div class="navbar navbar-default">
20
+ <div class="navbar-header">
21
+ <a class="navbar-brand" href="#">API Documentation</a>
22
+ </div>
23
+ <div class="navbar-collapse collapse">
24
+ <ul class="nav navbar-nav">
25
+ <li class="active"><a href="index.html">Home</a></li>
26
+ </ul>
27
+ </div>
28
+ </div>
29
+
30
+ <div class="row">
31
+ <div class="sidebar col-md-3 well">
32
+ <h5>Resources</h5>
33
+ <ul>
34
+ <% WSList.all.sort{|a,b| a.url <=> b.url}.each do |api| %>
35
+ <li><a href="#<%= "raw-#{api.verb}-#{api.url}" %>"><%= api.verb.upcase %> <%= api.url %></a></li>
36
+ <% end %>
37
+ </ul>
38
+ </div>
39
+ <div class="content col-md-9">
40
+ <div class="jumbotron">
41
+ <h1>API Documentation</h1>
42
+ <p>Resources are listed on the sidebar to the left.</p>
43
+ </div>
44
+
45
+ <% WSList.all.each do |api| %>
46
+ <div id="<%= "raw-#{api.verb}-#{api.url}" %>">
47
+ <div class="overall">
48
+ <h2><%= api.verb.upcase %> <%= '[SSL]' if api.ssl %> <%= api.url %></h2>
49
+ <% if api.auth_required %>
50
+ <span class='label label-danger'>Authentication required</span>
51
+ <% end %>
52
+
53
+ <% if api.doc.desc %>
54
+ <p>
55
+ <%= "#{api.doc.desc}" %>
56
+ </p>
57
+ <% end %>
58
+ </div>
59
+
60
+ <div class="parameters">
61
+ <h3>Parameters</h3>
62
+ <% if api.required_rules.any? || api.optional_rules.any? %>
63
+ <%= input_params_html(api.required_rules, api.optional_rules) %>
64
+ <% end %>
65
+
66
+ <ul class="list-unstyled">
67
+ <% api.params.namespaced_params.each do |params| %>
68
+ <li>
69
+ <strong><%= params.space_name.name %></strong>
70
+ <em>
71
+ (<%= params.space_name.null ? 'optional' : 'required' %>)
72
+ </em>
73
+ <%= input_params_html(params.list_required, params.list_optional) %>
74
+ </li>
75
+ <% end %>
76
+ </ul>
77
+ </div>
78
+
79
+ <div class="example-request">
80
+ <h3>Example Request</h3>
81
+ <% api.doc.examples.each do |example| %>
82
+ <pre class="example"><%= example %></pre>
83
+ <% end %>
84
+ </div>
85
+
86
+ <div class="response">
87
+ <% if api.response.nodes.any? %>
88
+ <h3>Response</h3>
89
+ <% if api.response.arrays %>
90
+ <span class="response-array">(Array, these are the properties of each array item)</span>
91
+ <% end %>
92
+
93
+ <% api.response.arrays.each do |array| %>
94
+ <%= response_element_html(array) %>
95
+ <% end %>
96
+ <% api.response.elements.each do |el| %>
97
+ <%= response_element_html(el) %>
98
+ <% end %>
99
+ <% end %>
100
+ <h4>Example</h4>
101
+ <pre><%= JSON.pretty_generate(JSON.parse(api.response.to_json)) %></pre>
102
+ </div>
103
+
104
+ </div>
105
+ <hr>
106
+ <% end %>
107
+
108
+ <footer>
109
+ <p>&copy; <%= Time.now.year %></p>
110
+ </footer>
111
+ </div>
112
+ </div>
113
+ </div>
114
+
115
+ <!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
116
+ <script src="https://code.jquery.com/jquery.js"></script>
117
+ <!-- Include all compiled plugins (below), or include individual files as needed -->
118
+ <script src="https://netdna.bootstrapcdn.com/bootstrap/3.0.0/js/bootstrap.min.js"></script>
119
+ </body>
120
+ </html>
@@ -0,0 +1,34 @@
1
+ # Extending the top level module to add some helpers
2
+ #
3
+ # @api public
4
+ class WeaselDiesel
5
+ module DSL
6
+ private
7
+
8
+ # Base DSL method called to describe a service
9
+ #
10
+ # @param [String] url The url of the service to add.
11
+ # @yield [WeaselDiesel] The newly created service.
12
+ # @return [Array] The services already defined
13
+ # @example Describing a basic service
14
+ # describe_service "hello-world.xml" do |service|
15
+ # # describe the service
16
+ # end
17
+ #
18
+ # @api public
19
+ def describe_service(url, &block)
20
+ service = WeaselDiesel.new(url)
21
+ yield service
22
+
23
+ service.sync_input_param_doc
24
+ WSList.add(service)
25
+
26
+ service
27
+ end
28
+
29
+ end
30
+ end
31
+
32
+ # Extend the main object with the DSL methods. This allows top-level calls
33
+ # without polluting the object inheritance tree.
34
+ self.extend WeaselDiesel::DSL
@@ -1,3 +1,3 @@
1
1
  class WeaselDiesel
2
- VERSION = "1.2.2"
2
+ VERSION = "1.3.0"
3
3
  end
@@ -7,14 +7,14 @@ describe_service "hello_world.xml" do |service|
7
7
 
8
8
  service.response do |response|
9
9
  response.element(:name => "greeting") do |e|
10
- e.attribute "message" => :string, :doc => "The greeting message sent back."
11
- end
10
+ e.attribute "message" => :string, :doc => "The greeting message sent back."
11
+ end
12
12
  end
13
13
 
14
14
  service.documentation do |doc|
15
- doc.overall "This service provides a simple hello world implementation example."
16
- doc.params :name, "The name of the person to greet."
17
- doc.example "<code>http://ps3.yourgame.com/hello_world.xml?name=Matt</code>"
15
+ doc.overall "This service provides a simple hello world implementation example."
16
+ doc.params :name, "The name of the person to greet."
17
+ doc.example "<code>http://ps3.yourgame.com/hello_world.xml?name=Matt</code>"
18
18
  end
19
19
 
20
20
  end
@@ -1,34 +1,34 @@
1
- require File.expand_path("spec_helper", File.dirname(__FILE__))
1
+ require_relative 'spec_helper'
2
2
 
3
3
  describe "WeaselDiesel JSON response description" do
4
4
 
5
5
  # JSON response example
6
6
  =begin
7
- { vouchers: [
8
- {
9
- id : 1,
7
+ { vouchers: [
8
+ {
9
+ id : 1,
10
10
  redeemed : false,
11
- created_at : 123123123123,
11
+ created_at : 123123123123,
12
12
  option: {
13
13
  id : 1231,
14
14
  price: 123.32
15
15
  }
16
- },
17
- {
18
- id : 2,
16
+ },
17
+ {
18
+ id : 2,
19
19
  redeemed : true,
20
- created_at : 123123123123,
20
+ created_at : 123123123123,
21
21
  option: {
22
22
  id : 1233,
23
23
  price: 1.32
24
24
  }
25
- },
25
+ },
26
26
  ] }
27
27
  =end
28
28
 
29
29
  before :all do
30
30
  @timestamp = Time.now.to_i
31
- @service = describe_service "json_list" do |service|
31
+ @service = describe_service "json_list" do |service|
32
32
  service.formats :json
33
33
  service.response do |response|
34
34
  response.array :vouchers do |node|
@@ -104,7 +104,7 @@ describe "WeaselDiesel JSON response description" do
104
104
  end
105
105
 
106
106
  it "should allow an anonymous object at the root of the response" do
107
- service = describe_service "json_anonymous_obj" do |service|
107
+ service = describe_service "json_anonymous_obj" do |service|
108
108
  service.formats :json
109
109
  service.response do |response|
110
110
  response.object do |obj|
@@ -120,7 +120,7 @@ describe "WeaselDiesel JSON response description" do
120
120
  obj.properties.find{|prop| prop.name == :id}.should_not be_nil
121
121
  obj.properties.find{|prop| prop.name == :foo}.should_not be_nil
122
122
  end
123
-
123
+
124
124
  end
125
125
 
126
126
 
@@ -134,7 +134,7 @@ describe "WeaselDiesel simple JSON object response description" do
134
134
 
135
135
  before :all do
136
136
  @timestamp = Time.now.to_i
137
- @service = describe_service "json_obj" do |service|
137
+ @service = describe_service "json_obj" do |service|
138
138
  service.formats :json
139
139
  service.response do |response|
140
140
  response.object :organization do |node|
@@ -165,7 +165,7 @@ describe "WeaselDiesel anonymous JSON object response description" do
165
165
 
166
166
  before :all do
167
167
  @timestamp = Time.now.to_i
168
- @service = describe_service "anon_json_obj" do |service|
168
+ @service = describe_service "anon_json_obj" do |service|
169
169
  service.formats :json
170
170
  service.response do |response|
171
171
  response.object do |node|
@@ -1,5 +1,5 @@
1
- require File.expand_path("spec_helper", File.dirname(__FILE__))
2
- require File.expand_path("../lib/json_response_verification", File.dirname(__FILE__))
1
+ require_relative 'spec_helper'
2
+ require_relative '../lib/json_response_verification'
3
3
 
4
4
  WeaselDiesel.send(:include, JSONResponseVerification)
5
5
 
@@ -70,7 +70,7 @@ describe ParamsVerification do
70
70
  params['timestamp'] = Time.now.iso8601
71
71
  lambda { ParamsVerification.validate!(params, @service.defined_params) }.should_not raise_error
72
72
  params['timestamp'] = Time.now.getutc.iso8601
73
- lambda { ParamsVerification.validate!(params, @service.defined_params) }.should_not raise_error(ParamsVerification::InvalidParamType)
73
+ lambda { ParamsVerification.validate!(params, @service.defined_params) }.should_not raise_error
74
74
  end
75
75
 
76
76
  it "should set the default value for a namespace optional param" do
@@ -111,7 +111,7 @@ describe ParamsVerification do
111
111
  it "should not raise an exception if a req array param doesn't contain a comma" do
112
112
  service = WSList.find(:post, "/services/array_param.xml")
113
113
  params = {'seq' => "a b c d e g"}
114
- lambda{ ParamsVerification.validate!(params, service.defined_params) }.should_not raise_exception(ParamsVerification::InvalidParamType)
114
+ lambda{ ParamsVerification.validate!(params, service.defined_params) }.should_not raise_exception
115
115
  end
116
116
 
117
117
  it "should raise an exception when a param is of the wrong type" do
@@ -1,9 +1,3 @@
1
- if RUBY_VERSION =~ /1.8/
2
- require 'rubygems'
3
- require 'backports'
4
- require 'json'
5
- end
6
-
7
1
  require 'rspec'
8
2
  require 'rack/test'
9
3
  require 'sinatra'
@@ -16,5 +10,6 @@ require_relative "../lib/framework_ext/sinatra_controller"
16
10
  ENV["RACK_ENV"] = 'test'
17
11
 
18
12
  RSpec.configure do |conf|
13
+ conf.include WeaselDiesel::DSL
19
14
  conf.include Rack::Test::Methods
20
15
  end
@@ -7,8 +7,8 @@ describe_service "services/test.xml" do |service|
7
7
  service.http_verb :get
8
8
 
9
9
  service.params do |p|
10
- p.string :framework,
11
- :in => WeaselDieselSpecOptions,
10
+ p.string :framework,
11
+ :in => WeaselDieselSpecOptions,
12
12
  :required => true,
13
13
  :doc => "The test framework used, could be one of the two following: #{WeaselDieselSpecOptions.join(", ")}."
14
14
 
@@ -38,7 +38,6 @@ describe_service "services/test.xml" do |service|
38
38
  # the response contains a list of player creation ratings each object in the list
39
39
 
40
40
  =begin
41
- #Format not supported by Ruby 1.8 due to hash insertion order not being maintained.
42
41
  service.response do |response|
43
42
  response.element(:name => "player_creation_ratings") do |e|
44
43
  e.attribute :id => :integer, :doc => "id doc"
@@ -1,4 +1,4 @@
1
- require File.expand_path("spec_helper", File.dirname(__FILE__))
1
+ require_relative 'spec_helper'
2
2
 
3
3
  describe "WeaselDiesel #controller_dispatch" do
4
4
 
@@ -1,4 +1,4 @@
1
- require File.expand_path("spec_helper", File.dirname(__FILE__))
1
+ require_relative 'spec_helper'
2
2
 
3
3
  describe WeaselDiesel::Documentation do
4
4
 
@@ -77,7 +77,9 @@ The most common way to use this service looks like that:
77
77
  it "should have a json representation of an response element" do
78
78
  json = @service.response.elements.first.to_json
79
79
  loaded_json = JSON.load(json)
80
- loaded_json[@service.response.elements.first.doc.name].should_not be_empty
80
+ loaded_json.has_key?(@service.response.elements.first.name).should be_true
81
+ loaded_json[@service.response.elements.first.name].should_not be_empty
82
+ loaded_json[@service.response.elements.first.name].has_key?("player_creation_rating").should be_true
81
83
  end
82
84
 
83
85
  it "should have documentation for a response element attribute" do
@@ -1,4 +1,4 @@
1
- require File.expand_path("spec_helper", File.dirname(__FILE__))
1
+ require_relative 'spec_helper'
2
2
 
3
3
  describe WeaselDiesel::Params do
4
4
 
@@ -69,7 +69,7 @@ describe WeaselDiesel::Params do
69
69
 
70
70
  it "should have options" do
71
71
  @rule.options[:type].should == :string
72
- @rule.options[:in].should == WeaselDieselSpecOptions
72
+ @rule.options[:in].should == WeaselDieselSpecOptions
73
73
  @rule.options[:null].should be_false
74
74
  end
75
75
  end
@@ -1,4 +1,4 @@
1
- require File.expand_path("spec_helper", File.dirname(__FILE__))
1
+ require_relative 'spec_helper'
2
2
 
3
3
  describe WeaselDiesel do
4
4
 
@@ -1,4 +1,4 @@
1
- require File.expand_path("spec_helper", File.dirname(__FILE__))
1
+ require_relative 'spec_helper'
2
2
 
3
3
  describe WSList do
4
4
 
@@ -1,6 +1,6 @@
1
- require File.expand_path("spec_helper", File.dirname(__FILE__))
1
+ require_relative 'spec_helper'
2
2
  require 'sinatra'
3
- require File.expand_path("./../lib/framework_ext/sinatra.rb", File.dirname(__FILE__))
3
+ require_relative '../lib/framework_ext/sinatra'
4
4
  WeaselDiesel.send(:include, WeaselDieselSinatraExtension)
5
5
 
6
6
  describe "Hello World example" do
@@ -10,6 +10,7 @@ Gem::Specification.new do |s|
10
10
  s.homepage = "https://github.com/mattetti/Weasel-Diesel"
11
11
  s.summary = %q{Web Service DSL}
12
12
  s.description = %q{Ruby DSL describing Web Services without implementation details.}
13
+ s.license = 'MIT'
13
14
 
14
15
  s.rubyforge_project = "wsdsl"
15
16
 
@@ -18,14 +19,12 @@ Gem::Specification.new do |s|
18
19
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
20
  s.require_paths = ["lib"]
20
21
 
22
+ s.add_dependency('thor')
23
+
21
24
  # specify any dependencies here; for example:
22
25
  s.add_development_dependency "rspec"
23
26
  s.add_development_dependency "rack-test"
24
27
  s.add_development_dependency "yard"
25
28
  s.add_development_dependency "sinatra"
26
- s.add_development_dependency "rake"
27
- if RUBY_VERSION =~ /1.8/
28
- s.add_runtime_dependency "backports"
29
- s.add_runtime_dependency "json"
30
- end
29
+ s.add_development_dependency "rake"
31
30
  end
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: weasel_diesel
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.2
4
+ version: 1.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matt Aimonetti
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-08-24 00:00:00.000000000 Z
11
+ date: 2013-08-30 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: thor
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '>='
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '>='
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: rspec
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -83,7 +97,8 @@ dependencies:
83
97
  description: Ruby DSL describing Web Services without implementation details.
84
98
  email:
85
99
  - mattaimonetti@gmail.com
86
- executables: []
100
+ executables:
101
+ - weasel_diesel
87
102
  extensions: []
88
103
  extra_rdoc_files: []
89
104
  files:
@@ -94,16 +109,21 @@ files:
94
109
  - LICENSE
95
110
  - README.md
96
111
  - Rakefile
112
+ - bin/weasel_diesel
97
113
  - lib/documentation.rb
98
114
  - lib/framework_ext/sinatra.rb
99
115
  - lib/framework_ext/sinatra_controller.rb
100
116
  - lib/inflection.rb
101
117
  - lib/json_response_verification.rb
102
- - lib/kernel_ext.rb
103
118
  - lib/params.rb
104
119
  - lib/params_verification.rb
105
120
  - lib/response.rb
106
121
  - lib/weasel_diesel.rb
122
+ - lib/weasel_diesel/cli.rb
123
+ - lib/weasel_diesel/doc_generator/_input_params.erb
124
+ - lib/weasel_diesel/doc_generator/_response_element.erb
125
+ - lib/weasel_diesel/doc_generator/template.erb
126
+ - lib/weasel_diesel/dsl.rb
107
127
  - lib/weasel_diesel/version.rb
108
128
  - lib/ws_list.rb
109
129
  - spec/hello_world_controller.rb
@@ -122,7 +142,8 @@ files:
122
142
  - spec/wsdsl_sinatra_ext_spec.rb
123
143
  - weasel_diesel.gemspec
124
144
  homepage: https://github.com/mattetti/Weasel-Diesel
125
- licenses: []
145
+ licenses:
146
+ - MIT
126
147
  metadata: {}
127
148
  post_install_message:
128
149
  rdoc_options: []
@@ -140,7 +161,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
140
161
  version: '0'
141
162
  requirements: []
142
163
  rubyforge_project: wsdsl
143
- rubygems_version: 2.0.3
164
+ rubygems_version: 2.0.7
144
165
  signing_key:
145
166
  specification_version: 4
146
167
  summary: Web Service DSL
@@ -1,27 +0,0 @@
1
- # Extending the top level module to add some helpers
2
- #
3
- # @api public
4
- module Kernel
5
-
6
- # Base DSL method called to describe a service
7
- #
8
- # @param [String] url The url of the service to add.
9
- # @yield [WeaselDiesel] The newly created service.
10
- # @return [Array] The services already defined
11
- # @example Describing a basic service
12
- # describe_service "hello-world.xml" do |service|
13
- # # describe the service
14
- # end
15
- #
16
- # @api public
17
- def describe_service(url, &block)
18
- service = WeaselDiesel.new(url)
19
- yield service
20
-
21
- service.sync_input_param_doc
22
- WSList.add(service)
23
-
24
- service
25
- end
26
-
27
- end