weasel_diesel 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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