weasel_diesel 1.0.0

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/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in weasel_diesel.gemspec
4
+ gemspec
@@ -0,0 +1,38 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ wsdsl (1.0.0)
5
+
6
+ GEM
7
+ remote: http://rubygems.org/
8
+ specs:
9
+ diff-lcs (1.1.3)
10
+ rack (1.4.1)
11
+ rack-protection (1.2.0)
12
+ rack
13
+ rack-test (0.6.1)
14
+ rack (>= 1.0)
15
+ rspec (2.9.0)
16
+ rspec-core (~> 2.9.0)
17
+ rspec-expectations (~> 2.9.0)
18
+ rspec-mocks (~> 2.9.0)
19
+ rspec-core (2.9.0)
20
+ rspec-expectations (2.9.1)
21
+ diff-lcs (~> 1.1.3)
22
+ rspec-mocks (2.9.0)
23
+ sinatra (1.3.2)
24
+ rack (~> 1.3, >= 1.3.6)
25
+ rack-protection (~> 1.2)
26
+ tilt (~> 1.3, >= 1.3.3)
27
+ tilt (1.3.3)
28
+ yard (0.7.5)
29
+
30
+ PLATFORMS
31
+ ruby
32
+
33
+ DEPENDENCIES
34
+ rack-test
35
+ rspec
36
+ sinatra
37
+ wsdsl!
38
+ yard
data/LICENSE ADDED
@@ -0,0 +1,23 @@
1
+ Copyright (c) 2012 Matt Aimonetti
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
22
+ --
23
+
@@ -0,0 +1,231 @@
1
+ # Web Service DSL
2
+
3
+ Weasel Diesel is a simple DSL allowing developers to simply describe and
4
+ document their web APIS.
5
+ The DSL is already setup on top of Sinatra in this [example
6
+ application](https://github.com/mattetti/sinatra-web-api-example) that
7
+ you can simply fork and use as a base for your application.
8
+
9
+ DSL examples:
10
+
11
+ ``` ruby
12
+ describe_service "hello_world" do |service|
13
+ service.formats :json
14
+ service.http_verb :get
15
+ service.disable_auth # on by default
16
+
17
+ # INPUT
18
+ service.param.string :name, :default => 'World'
19
+
20
+ # OUTPUT
21
+ service.response do |response|
22
+ response.object do |obj|
23
+ obj.string :message, :doc => "The greeting message sent back. Defaults to 'World'"
24
+ obj.datetime :at, :doc => "The timestamp of when the message was dispatched"
25
+ end
26
+ end
27
+
28
+ # DOCUMENTATION
29
+ service.documentation do |doc|
30
+ doc.overall "This service provides a simple hello world implementation example."
31
+ doc.param :name, "The name of the person to greet."
32
+ doc.example "<code>curl -I 'http://localhost:9292/hello_world?name=Matt'</code>"
33
+ end
34
+
35
+ # ACTION/IMPLEMENTATION (specific to the sinatra app example, can
36
+ # instead be set to call a controller action)
37
+ service.implementation do
38
+ {:message => "Hello #{params[:name]}", :at => Time.now}.to_json
39
+ end
40
+
41
+ end
42
+ ```
43
+
44
+ ``` ruby
45
+ describe_service "hello_world" do |service|
46
+ service.formats :xml
47
+ service.http_verb :get
48
+ service.disable_auth # on by default
49
+
50
+ service.param.string :name, :default => 'World'
51
+
52
+ service.response do |response|
53
+ response.element(:name => "greeting") do |e|
54
+ e.attribute "message" => :string, :doc => "The greeting message sent back."
55
+ end
56
+ end
57
+
58
+ service.documentation do |doc|
59
+ doc.overall "This service provides a simple hello world implementation example."
60
+ doc.params :name, "The name of the person to greet."
61
+ doc.example "<code>http://example.com/hello_world.xml?name=Matt</code>"
62
+ end
63
+
64
+ end
65
+ ```
66
+
67
+ Or a more complex example:
68
+
69
+ ``` ruby
70
+ SpecOptions = ['RSpec', 'Bacon'] # usually pulled from a model
71
+
72
+ describe_service "wsdsl/test.xml" do |service|
73
+ service.formats :xml, :json
74
+ service.http_verb :get
75
+
76
+ service.params do |p|
77
+ p.string :framework, :in => SpecOptions, :null => false, :required => true
78
+
79
+ p.datetime :timestamp, :default => Time.now
80
+ p.string :alpha, :in => ['a', 'b', 'c']
81
+ p.string :version, :null => false
82
+ p.integer :num, :minvalue => 42
83
+ end
84
+
85
+ # service.param :delta, :optional => true, :type => 'float'
86
+ # All params are optional by default.
87
+ # service.param :epsilon, :type => 'string'
88
+
89
+ service.params.namespace :user do |user|
90
+ user.integer :id, :required => :true
91
+ end
92
+
93
+ # the response contains a list of player creation ratings each object in the list
94
+
95
+ service.response do |response|
96
+ response.element(:name => "player_creation_ratings") do |e|
97
+ e.attribute :id => :integer, :doc => "id doc"
98
+ e.attribute :is_accepted => :boolean, :doc => "is accepted doc"
99
+ e.attribute :name => :string, :doc => "name doc"
100
+
101
+ e.array :name => 'player_creation_rating', :type => 'PlayerCreationRating' do |a|
102
+ a.attribute :comments => :string, :doc => "comments doc"
103
+ a.attribute :player_id => :integer, :doc => "player_id doc"
104
+ a.attribute :rating => :integer, :doc => "rating doc"
105
+ a.attribute :username => :string, :doc => "username doc"
106
+ end
107
+ end
108
+ end
109
+
110
+ service.documentation do |doc|
111
+ # doc.overall <markdown description text>
112
+ doc.overall <<-DOC
113
+ This is a test service used to test the framework.
114
+ DOC
115
+
116
+ # doc.params <name>, <definition>
117
+ doc.params :framework, "The test framework used, could be one of the two following: #{SpecOptions.join(", ")}."
118
+ doc.params :version, "The version of the framework to use."
119
+
120
+ # doc.example <markdown text>
121
+ doc.example <<-DOC
122
+ The most common way to use this service looks like that:
123
+ http://example.com/wsdsl/test.xml?framework=rspec&version=2.0.0
124
+ DOC
125
+ end
126
+ end
127
+ ```
128
+
129
+ ## JSON APIs
130
+
131
+ This library was designed with XML responses in mind and JSON support
132
+ was added later on which explains why some response methods are aliases.
133
+ Consider the following JSON response:
134
+
135
+ ``` json
136
+ { people: [
137
+ {
138
+ id : 1,
139
+ online : false,
140
+ created_at : 123123123123,
141
+ team : {
142
+ id : 1231,
143
+ score : 123.32
144
+ }
145
+ },
146
+ {
147
+ id : 2,
148
+ online : true,
149
+ created_at : 123123123123,
150
+ team: {
151
+ id : 1233,
152
+ score : 1.32
153
+ }
154
+ },
155
+ ] }
156
+
157
+ It would be described as follows:
158
+
159
+ ``` ruby
160
+ describe_service "json_list" do |service|
161
+ service.formats :json
162
+ service.response do |response|
163
+ response.array :people do |node|
164
+ node.integer :id
165
+ node.boolean :online
166
+ node.datetime :created_at
167
+ node.object :team do |team|
168
+ team.integer :id
169
+ team.float :score, :null => true
170
+ end
171
+ end
172
+ end
173
+ end
174
+ ```
175
+
176
+ Nodes/elements can also use some meta attributes. Currently the
177
+ following meta attributes are available:
178
+
179
+ * key (refers to an attribute name that is key to this object)
180
+ * type (refers to the type of object described, valuable when using JSON
181
+ cross OO based apps.
182
+
183
+ JSON response validation can be done using an optional module.
184
+ Look at the spec/json_response_verification_spec.rb file for a complete
185
+ example. The goal of this module is to help automate API testing by
186
+ validating the data structure of the returned object.
187
+
188
+ ## Test suite
189
+
190
+ This library comes with a test suite requiring Ruby 1.9.2
191
+ The following gems need to be available:
192
+ Rspec, Rack, Sinatra
193
+
194
+ ## RUBY 1.8 warning
195
+
196
+ This library was written for Ruby 1.9 and 1.8 support was added later on
197
+ via the backports libary and some tweaks. However, because unlike in
198
+ ruby 1.9, the hash insert order isn't kept in 1.8 the following syntax
199
+ isn't supported and the alternative version needs to be used:
200
+
201
+ ``` ruby
202
+ service.response do |response|
203
+ response.element(:name => "player_creation_ratings") do |e|
204
+ e.attribute :id => :integer, :doc => "id doc"
205
+ e.attribute :is_accepted => :boolean, :doc => "is accepted doc"
206
+ e.attribute :name => :string, :doc => "name doc"
207
+ end
208
+ end
209
+ ```
210
+
211
+ Instead the following version should be used:
212
+
213
+ ``` ruby
214
+ service.response do |response|
215
+ response.element(:name => "player_creation_ratings") do |e|
216
+ e.integer :id, :doc => "id doc"
217
+ e.boolean :is_accepted, :doc => "is accepted doc"
218
+ e.string :name, :doc => "name doc"
219
+ end
220
+ end
221
+ ```
222
+
223
+ Both code snippets do the exact same thing but the first version is 1.9
224
+ only.
225
+
226
+
227
+
228
+ ## Copyright
229
+
230
+ Copyright (c) 2012 Matt Aimonetti. See LICENSE for
231
+ further details.
@@ -0,0 +1,12 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ require 'rspec/core'
4
+ require 'rspec/core/rake_task'
5
+ RSpec::Core::RakeTask.new(:spec) do |spec|
6
+ spec.pattern = FileList['spec/**/*_spec.rb']
7
+ end
8
+
9
+ task :default => :spec
10
+
11
+ require 'yard'
12
+ YARD::Rake::YardocTask.new
@@ -0,0 +1,151 @@
1
+ class WeaselDiesel
2
+ # Service documentation class
3
+ #
4
+ # @api public
5
+ class Documentation
6
+
7
+ # @api public
8
+ attr_reader :desc
9
+
10
+ # @api public
11
+ attr_reader :params_doc
12
+
13
+ # @api public
14
+ attr_reader :namespaced_params
15
+
16
+ # @api public
17
+ attr_reader :examples
18
+
19
+ # @api public
20
+ attr_reader :elements
21
+
22
+ # This class contains the documentation information regarding an element.
23
+ # Currently, elements are only used in the response info.
24
+ #
25
+ # @api public
26
+ class ElementDoc
27
+
28
+ # @api public
29
+ attr_reader :name, :attributes
30
+
31
+ # @param [String] The element's name
32
+ # @api public
33
+ def initialize(name)
34
+ # raise ArgumentError, "An Element doc needs to be initialize by passing a hash with a ':name' keyed entry." unless opts.is_a?(Hash) && opts.has_key?(:name)
35
+ @name = name
36
+ @attributes = {}
37
+ end
38
+
39
+ # @param [String] name The name of the attribute described
40
+ # @param [String] desc The description of the attribute
41
+ # @api public
42
+ def attribute(name, desc)
43
+ @attributes[name] = desc
44
+ end
45
+
46
+ end # of ElementDoc
47
+
48
+ # Namespaced param documentation
49
+ #
50
+ # @api public
51
+ class NamespacedParam
52
+
53
+ # @return [String, Symbol] The name of the namespaced, usually a symbol
54
+ # @api public
55
+ attr_reader :name
56
+
57
+ # @return [Hash] The list of params within the namespace
58
+ # @api public
59
+ attr_reader :params
60
+
61
+ # @api public
62
+ def initialize(name)
63
+ @name = name
64
+ @params = {}
65
+ end
66
+
67
+ # Sets the description/documentation of a specific namespaced param
68
+ #
69
+ # @return [String]
70
+ # @api public
71
+ def param(name, desc)
72
+ @params[name] = desc
73
+ end
74
+
75
+ end
76
+
77
+ # Initialize a Documentation object wrapping all the documentation aspect of the service.
78
+ # The response documentation is a Documentation instance living inside the service documentation object.
79
+ #
80
+ # @api public
81
+ def initialize
82
+ @params_doc = {}
83
+ @examples = []
84
+ @elements = []
85
+ @namespaced_params = []
86
+ end
87
+
88
+ # Sets or returns the overall description
89
+ #
90
+ # @param [String] desc Service overall description
91
+ # @api public
92
+ # @return [String] The overall service description
93
+ def overall(desc)
94
+ if desc.nil?
95
+ @desc
96
+ else
97
+ @desc = desc
98
+ end
99
+ end
100
+
101
+ # Sets the description/documentation of a specific param
102
+ #
103
+ # @return [String]
104
+ # @api public
105
+ def params(name, desc)
106
+ @params_doc[name] = desc
107
+ end
108
+ alias_method :param, :params
109
+
110
+ # Define a new namespaced param and yield it to the passed block
111
+ # if available.
112
+ #
113
+ # @return [Array] the namespaced params
114
+ # @api public
115
+ def namespace(ns_name)
116
+ new_ns_param = NamespacedParam.new(ns_name)
117
+ if block_given?
118
+ yield(new_ns_param)
119
+ end
120
+ @namespaced_params << new_ns_param
121
+ end
122
+
123
+ def response
124
+ @response ||= Documentation.new
125
+ end
126
+
127
+ # Service usage example
128
+ #
129
+ # @param [String] desc Usage example.
130
+ # @return [Array<String>] All the examples.
131
+ # @api public
132
+ def example(desc)
133
+ @examples << desc
134
+ end
135
+
136
+ # Add a new element to the doc
137
+ # currently only used for response doc
138
+ #
139
+ # @param [Hash] opts element's documentation options
140
+ # @yield [ElementDoc] The new element doc.
141
+ # @return [Array<ElementDoc>]
142
+ # @api public
143
+ def element(opts={})
144
+ element = ElementDoc.new(opts)
145
+ yield(element)
146
+ @elements << element
147
+ end
148
+
149
+
150
+ end # of Documentation
151
+ end