weasel_diesel 1.1.4 → 1.2.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.
@@ -13,4 +13,4 @@ rvm:
13
13
 
14
14
  matrix:
15
15
  allow_failures:
16
- - ruby-head
16
+ - rvm: ruby-head
@@ -0,0 +1,20 @@
1
+ # WeaselDiesel Changelog
2
+
3
+ All changes can be seen on GitHub and git tags are used to isolate each
4
+ release.
5
+
6
+ **1.2.0**:
7
+
8
+ * All service urls are now stored with a prepended slash (if not defined
9
+ with one). `WDList.find(<verb>, <url>)` will automatically find the
10
+ right url even if the passed url doesn't start by a '/'. This should be
11
+ backward compatible with most code out there as long as your code
12
+ doesn't do a direct lookup on the url.
13
+ The reason for this change is that I think I made a design mistake when
14
+ I decided to define urls without a leading '/'. Sinatra and many other
15
+ frameworks use that leading slash and it makes sense to do the same.
16
+
17
+ * Adding a duplicate service (same url and verb) now raises an exception
18
+ instead of silently ignoring the duplicate.
19
+
20
+ * Upgraded test suite to properly use `WDList.find`.
data/README.md CHANGED
@@ -16,9 +16,9 @@ you can fork and use as a base for your application.
16
16
  DSL examples:
17
17
 
18
18
  ``` ruby
19
- describe_service "hello_world" do |service|
19
+ describe_service "/hello_world" do |service|
20
20
  service.formats :json
21
- service.http_verb :get
21
+ service.http_verb :get # default verb, can be ommitted.
22
22
  service.disable_auth # on by default
23
23
 
24
24
  # INPUT
@@ -52,7 +52,7 @@ Or a more complex example using XML:
52
52
  ``` ruby
53
53
  SpecOptions = ['RSpec', 'Bacon'] # usually pulled from a model
54
54
 
55
- describe_service "wsdsl/test.xml" do |service|
55
+ describe_service "/wsdsl/test.xml" do |service|
56
56
  service.formats :xml, :json
57
57
  service.http_verb :get
58
58
 
@@ -262,7 +262,7 @@ Consider the following JSON response:
262
262
  It would be described as follows:
263
263
 
264
264
  ``` ruby
265
- describe_service "json_list" do |service|
265
+ describe_service "/json_list" do |service|
266
266
  service.formats :json
267
267
  service.response do |response|
268
268
  response.array :people do |node|
@@ -11,12 +11,12 @@ module WeaselDieselSinatraExtension
11
11
  def load_sinatra_route
12
12
  service = self
13
13
  upcase_verb = service.verb.to_s.upcase
14
- puts "/#{self.url} -> #{self.controller_name}##{self.action} - (#{upcase_verb})"
14
+ puts "#{self.url} -> #{self.controller_name}##{self.action} - (#{upcase_verb})"
15
15
 
16
16
  # Define the route directly to save some object allocations on the critical path
17
17
  # Note that we are using a private API to define the route and that unlike sinatra usual DSL
18
18
  # we do NOT define a HEAD route for every GET route.
19
- Sinatra::Base.send(:route, upcase_verb, "/#{self.url}") do
19
+ Sinatra::Base.send(:route, upcase_verb, self.url) do
20
20
  service.controller_dispatch(self)
21
21
  end
22
22
 
@@ -0,0 +1,27 @@
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
@@ -3,6 +3,7 @@ require File.expand_path('params', File.dirname(__FILE__))
3
3
  require File.expand_path('response', File.dirname(__FILE__))
4
4
  require File.expand_path('documentation', File.dirname(__FILE__))
5
5
  require File.expand_path('ws_list', File.dirname(__FILE__))
6
+ require File.expand_path('kernel_ext', File.dirname(__FILE__))
6
7
 
7
8
  # WeaselDiesel offers a web service DSL to define web services,
8
9
  # their params, http verbs, formats expected as well as the documentation
@@ -117,14 +118,15 @@ class WeaselDiesel
117
118
 
118
119
  # Service constructor which is usually used via {Kernel#describe_service}
119
120
  #
120
- # @param [String] url Service's url
121
+ # @param [String] url Service's url ( the url will automatically be prepended a slash if it doesn't already contain one.
121
122
  # @see #describe_service See how this class is usually initialized using `describe_service`
122
123
  # @api public
123
124
  def initialize(url)
124
- @url = url
125
+ @url = url.start_with?('/') ? url : "/#{url}"
125
126
  @defined_params = WeaselDiesel::Params.new
126
127
  @doc = WeaselDiesel::Documentation.new
127
128
  @response = WeaselDiesel::Response.new
129
+ # TODO: extract to its own optional lib
128
130
  if WeaselDiesel.use_controller_dispatch
129
131
  @name = extract_service_root_name(url)
130
132
  if WeaselDiesel.use_pluralized_controllers
@@ -135,6 +137,7 @@ class WeaselDiesel
135
137
  end
136
138
  @action = extract_service_action(url)
137
139
  end
140
+ #
138
141
  @verb = :get
139
142
  @formats = []
140
143
  @version = '0.1'
@@ -169,6 +172,7 @@ class WeaselDiesel
169
172
  # @return [Boolean] The updated value, default to false
170
173
  # @api public
171
174
  # @since 0.3.0
175
+ # @deprecated
172
176
  def self.use_controller_dispatch
173
177
  @controller_dispatch
174
178
  end
@@ -180,6 +184,7 @@ class WeaselDiesel
180
184
  # @return [Boolean] The updated value
181
185
  # @api public
182
186
  # @since 0.1.1
187
+ # @deprecated
183
188
  def self.use_controller_dispatch=(val)
184
189
  @controller_dispatch = val
185
190
  end
@@ -192,6 +197,7 @@ class WeaselDiesel
192
197
  #
193
198
  # @return [#to_s] The response from the controller action
194
199
  # @api private
200
+ # @deprecated
195
201
  def controller_dispatch(app)
196
202
  unless @controller
197
203
  klass = @controller_name.split("::")
@@ -419,31 +425,3 @@ class WeaselDiesel
419
425
 
420
426
 
421
427
  end
422
-
423
- # Extending the top level module to add some helpers
424
- #
425
- # @api public
426
- module Kernel
427
-
428
- # Base DSL method called to describe a service
429
- #
430
- # @param [String] url The url of the service to add.
431
- # @yield [WeaselDiesel] The newly created service.
432
- # @return [Array] The services already defined
433
- # @example Describing a basic service
434
- # describe_service "hello-world.xml" do |service|
435
- # # describe the service
436
- # end
437
- #
438
- # @api public
439
- def describe_service(url, &block)
440
- service = WeaselDiesel.new(url)
441
- yield service
442
-
443
- service.sync_input_param_doc
444
- WSList.add(service)
445
-
446
- service
447
- end
448
-
449
- end
@@ -1,3 +1,3 @@
1
1
  class WeaselDiesel
2
- VERSION = "1.1.4"
2
+ VERSION = "1.2.0"
3
3
  end
@@ -4,6 +4,7 @@
4
4
  module WSList
5
5
 
6
6
  class UnknownService < StandardError; end
7
+ class DuplicateServiceDescription < StandardError; end
7
8
 
8
9
  module_function
9
10
 
@@ -12,10 +13,14 @@ module WSList
12
13
  #
13
14
  # @param [WeaselDiesel] The service to add.
14
15
  # @return [Array<WeaselDiesel>] All the added services.
16
+ # @raise DuplicateServiceDescription If a service is being duplicated.
15
17
  # @api public
16
18
  def add(service)
17
19
  @list ||= []
18
- @list << service unless @list.find{|s| s.url == service.url && s.verb == service.verb}
20
+ if WSList.find(service.verb, service.url)
21
+ raise DuplicateServiceDescription, "A service accessible via #{service.verb} #{service.url} already exists"
22
+ end
23
+ @list << service
19
24
  @list
20
25
  end
21
26
 
@@ -34,6 +39,7 @@ module WSList
34
39
  # @return [WeaselDiesel] The found service.
35
40
  #
36
41
  # @api public
42
+ # @deprecated
37
43
  def named(name)
38
44
  service = all.find{|service| service.name == name}
39
45
  if service.nil?
@@ -49,6 +55,8 @@ module WSList
49
55
  # @return [Nil, WeaselDiesel] The found service.
50
56
  #
51
57
  # @api public
58
+ # @deprecated use #find instead since this method doesn't support a verb being passed
59
+ # and the url might or might not match depending on the leading slash.
52
60
  def [](url)
53
61
  @list.find{|service| service.url == url}
54
62
  end
@@ -62,7 +70,8 @@ module WSList
62
70
  # @api public
63
71
  def find(verb, url)
64
72
  verb = verb.to_s.downcase.to_sym
65
- @list.find{|service| service.verb == verb && service.url == url}
73
+ slashed_url = url.start_with?('/') ? url : "/#{url}"
74
+ @list.find{|service| service.verb == verb && service.url == slashed_url}
66
75
  end
67
76
 
68
77
 
@@ -3,7 +3,7 @@ require_relative "spec_helper"
3
3
  describe ParamsVerification do
4
4
 
5
5
  before :all do
6
- @service = WSList.all.find{|s| s.url == 'services/test.xml'}
6
+ @service = WSList.find(:get, '/services/test.xml')
7
7
  @service.should_not be_nil
8
8
  @valid_params = {'framework' => 'RSpec', 'version' => '1.02', 'user' => {'id' => '123', 'groups' => 'manager,developer', 'skills' => 'java,ruby'}}
9
9
  end
@@ -87,7 +87,7 @@ describe ParamsVerification do
87
87
  end
88
88
 
89
89
  it "should cast a comma delimited string into an array when param marked as an array" do
90
- service = WSList.all.find{|s| s.url == "services/array_param.xml"}
90
+ service = WSList.find(:post, "/services/array_param.xml")
91
91
  service.should_not be_nil
92
92
  params = {'seq' => "a,b,c,d,e,g"}
93
93
  validated = ParamsVerification.validate!(params, service.defined_params)
@@ -95,7 +95,7 @@ describe ParamsVerification do
95
95
  end
96
96
 
97
97
  it "should not raise an exception if a req array param doesn't contain a comma" do
98
- service = WSList.all.find{|s| s.url == "services/array_param.xml"}
98
+ service = WSList.find(:post, "/services/array_param.xml")
99
99
  params = {'seq' => "a b c d e g"}
100
100
  lambda{ ParamsVerification.validate!(params, service.defined_params) }.should_not raise_exception(ParamsVerification::InvalidParamType)
101
101
  end
@@ -144,7 +144,7 @@ describe ParamsVerification do
144
144
  lambda{ ParamsVerification.validate!(params, @service.defined_params) }.should raise_exception(ParamsVerification::InvalidParamValue)
145
145
  # other service
146
146
  params = {'preference' => {'region_code' => 'us', 'language_code' => 'de'}}
147
- service = WSList.all.find{|s| s.url == 'preferences.xml'}
147
+ service = WSList.find(:get, '/preferences.xml')
148
148
  service.should_not be_nil
149
149
  lambda{ ParamsVerification.validate!(params, service.defined_params) }.should raise_exception(ParamsVerification::InvalidParamValue)
150
150
  end
@@ -158,7 +158,7 @@ describe ParamsVerification do
158
158
  end
159
159
 
160
160
  it "should validate that no params are passed when accept_no_params! is set on a service" do
161
- service = WSList.all.find{|s| s.url == "services/test_no_params.xml"}
161
+ service = WSList.find(:get, "/services/test_no_params.xml")
162
162
  service.should_not be_nil
163
163
  params = copy(@valid_params)
164
164
  lambda{ ParamsVerification.validate!(params, service.defined_params) }.should raise_exception
@@ -173,7 +173,7 @@ describe ParamsVerification do
173
173
  it "should prevent XSS attack on unexpected param name being listed in the exception message" do
174
174
  params = copy(@valid_params)
175
175
  params["7e22c<script>alert('xss vulnerability')</script>e88ff3f0952"] = 1
176
- escaped_error_message = /7e22c&lt;script&gt;alert\('xss vulnerability'\)&lt;\/script&gt;e88ff3f0952/
176
+ escaped_error_message = /7e22c&lt;script&gt;alert\(.*\)&lt;\/script&gt;e88ff3f0952/
177
177
  lambda{ ParamsVerification.validate!(params, @service.defined_params) }.should raise_exception(ParamsVerification::UnexpectedParam, escaped_error_message)
178
178
  end
179
179
 
@@ -127,3 +127,11 @@ describe_service "services/array_param.xml" do |s|
127
127
  end
128
128
 
129
129
  end
130
+
131
+ describe_service "/slash/foo" do |service|
132
+ service.formats :json
133
+ end
134
+
135
+ describe_service "/" do |service|
136
+ service.extra["name"] = "root"
137
+ end
@@ -3,7 +3,7 @@ require File.expand_path("spec_helper", File.dirname(__FILE__))
3
3
  describe "WeaselDiesel #controller_dispatch" do
4
4
 
5
5
  before :all do
6
- @service = WSList.all.find{|s| s.url == 'services/test.xml'}
6
+ @service = WSList.find(:get, '/services/test.xml')
7
7
  @service.should_not be_nil
8
8
  end
9
9
 
@@ -46,7 +46,7 @@ describe "WeaselDiesel #controller_dispatch" do
46
46
 
47
47
  it "should be able to dispatch controller" do
48
48
  describe_service("projects.xml") { |s| }
49
- service = WSList["projects.xml"]
49
+ service = WSList.find(:get, "projects.xml")
50
50
  service.controller_dispatch("application").
51
51
  should == ["application", "projects", "list"]
52
52
  end
@@ -62,10 +62,10 @@ describe "WeaselDiesel #controller_dispatch" do
62
62
  service.action = "list"
63
63
  end
64
64
 
65
- service = WSList["project/:project_id/tasks.xml"]
65
+ service = WSList.find(:get, "project/:project_id/tasks.xml")
66
66
  service.controller_dispatch("application").should == ["application", "project", "list"]
67
67
 
68
- service = WSList["project/:project_id/task/:task_id/items.xml"]
68
+ service = WSList.find(:get, "project/:project_id/task/:task_id/items.xml")
69
69
  service.controller_dispatch("application").should == ["application", "project", "list"]
70
70
  end
71
71
 
@@ -74,7 +74,7 @@ describe "WeaselDiesel #controller_dispatch" do
74
74
  service.controller_name = "UnknownController"
75
75
  service.action = "list"
76
76
  end
77
- service = WSList["unknown.xml"]
77
+ service = WSList.find(:get, "unknown.xml")
78
78
  lambda { service.controller_dispatch("application") }.
79
79
  should raise_error("The UnknownController class was not found")
80
80
  end
@@ -87,7 +87,7 @@ describe "WeaselDiesel #controller_dispatch" do
87
87
  WSList.all.clear
88
88
  WeaselDiesel.use_controller_dispatch = true
89
89
  load File.expand_path('test_services.rb', File.dirname(__FILE__))
90
- @c_service = WSList.all.find{|s| s.url == 'services/test.xml'}
90
+ @c_service = WSList.find(:get, '/services/test.xml')
91
91
  @c_service.should_not be_nil
92
92
  end
93
93
  after :all do
@@ -110,7 +110,7 @@ describe "WeaselDiesel #controller_dispatch" do
110
110
  end
111
111
 
112
112
  it "should support restful routes based on the HTTP verb" do
113
- service = WSList.all.find{|s| s.url == "services.xml"}
113
+ service = WSList.find(:put, "/services.xml")
114
114
  service.should_not be_nil
115
115
  service.http_verb.should == :put
116
116
  service.action.should_not be_nil
@@ -151,7 +151,7 @@ describe "WeaselDiesel #controller_dispatch" do
151
151
  service.controller_name = "CustomController"
152
152
  service.action = "foo"
153
153
  end
154
- service = WSList.all.find{|s| s.url == "players/:id.xml"}
154
+ service = WSList.find(:get, "players/:id.xml")
155
155
  service.controller_name.should == "CustomController"
156
156
  service.action.should == "foo"
157
157
  end
@@ -3,7 +3,7 @@ require File.expand_path("spec_helper", File.dirname(__FILE__))
3
3
  describe WeaselDiesel::Documentation do
4
4
 
5
5
  before :all do
6
- @service = WSList.all.find{|s| s.url == 'services/test.xml'}
6
+ @service = WSList.find(:get, '/services/test.xml')
7
7
  @service.should_not be_nil
8
8
  @doc = @service.doc
9
9
  @doc.should_not be_nil
@@ -31,7 +31,7 @@ describe WeaselDiesel::Documentation do
31
31
  end
32
32
 
33
33
  it "should allow to define namespaced params doc" do
34
- service = WSList.all.find{|s| s.url == "services.xml"}
34
+ service = WSList.find(:put, "/services.xml")
35
35
  service.documentation do |doc|
36
36
  doc.namespace :preference do |ns|
37
37
  ns.param :id, "Ze id."
@@ -44,7 +44,7 @@ describe WeaselDiesel::Documentation do
44
44
  end
45
45
 
46
46
  it "should allow object to be an alias for namespace params" do
47
- service = WSList.all.find{|s| s.url == "services.xml"}
47
+ service = WSList.find(:put, "/services.xml")
48
48
  service.documentation do |doc|
49
49
  doc.object :preference do |ns|
50
50
  ns.param :id, "Ze id."
@@ -149,7 +149,7 @@ The most common way to use this service looks like that:
149
149
  end
150
150
 
151
151
  it "should have the param documented" do
152
- service = WSList["legacy_param_doc"]
152
+ service = WSList.find(:get, "legacy_param_doc")
153
153
  service.doc.params_doc.keys.sort.should == [:framework, :version]
154
154
  service.doc.params_doc[service.doc.params_doc.keys.first].should_not be_nil
155
155
  end
@@ -3,7 +3,7 @@ require File.expand_path("spec_helper", File.dirname(__FILE__))
3
3
  describe WeaselDiesel::Params do
4
4
 
5
5
  before :all do
6
- @service = WSList.all.find{|s| s.url == 'services/test.xml'}
6
+ @service = WSList.find(:get, '/services/test.xml')
7
7
  @service.should_not be_nil
8
8
  @sparams = @service.params
9
9
  end
@@ -31,7 +31,7 @@ describe WeaselDiesel::Params do
31
31
  end
32
32
 
33
33
  it "should allow to define namespaced param" do
34
- service = WSList.all.find{|s| s.url == "services.xml"}
34
+ service = WSList.find(:put, "/services.xml")
35
35
  service.params do |params|
36
36
  params.namespace :preference do |ns|
37
37
  ns.param :id, "Ze id."
@@ -44,7 +44,7 @@ describe WeaselDiesel::Params do
44
44
  end
45
45
 
46
46
  it "should allow object as an alias to namespaced param" do
47
- service = WSList.all.find{|s| s.url == "services.xml"}
47
+ service = WSList.find(:put, "/services.xml")
48
48
  service.params do |params|
49
49
  params.object :preference do |ns|
50
50
  ns.param :id, "Ze id."
@@ -3,13 +3,13 @@ require File.expand_path("spec_helper", File.dirname(__FILE__))
3
3
  describe WeaselDiesel do
4
4
 
5
5
  before :all do
6
- @service = WSList.all.find{|s| s.url == 'services/test.xml'}
6
+ @service = WSList.find(:get, '/services/test.xml')
7
7
  @service.should_not be_nil
8
8
  end
9
9
 
10
10
  it "should have an url" do
11
11
  # dummy test since that's how we found the service, but oh well
12
- @service.url.should == 'services/test.xml'
12
+ @service.url.should == '/services/test.xml'
13
13
  end
14
14
 
15
15
  it "should have some http verbs defined" do
@@ -40,4 +40,14 @@ describe WeaselDiesel do
40
40
  @service.doc.should be_an_instance_of(WeaselDiesel::Documentation)
41
41
  end
42
42
 
43
+ it "should store urls with a leading slash" do
44
+ service = WeaselDiesel.new("/foo")
45
+ service.url.should == "/foo"
46
+ service.url.should == WeaselDiesel.new("foo").url
47
+ WeaselDiesel.new("foo").url.should_not == WeaselDiesel.new("foo/").url
48
+
49
+ root = WeaselDiesel.new("/")
50
+ root.url.should == "/"
51
+ end
52
+
43
53
  end
@@ -5,12 +5,36 @@ describe WSList do
5
5
  it "find service by verb/route" do
6
6
  service = WSList.find(:get, 'services/test.xml')
7
7
  service.should_not be_nil
8
-
9
- service.url.should == 'services/test.xml'
8
+ service.url.should == '/services/test.xml'
10
9
  service.verb.should == :get
11
10
 
12
11
  service = WSList.find(:delete, 'services/test.xml')
13
- service.url.should == 'services/test.xml'
12
+ service.url.should == '/services/test.xml'
14
13
  service.verb.should == :delete
15
14
  end
15
+
16
+ it "finds service without or without the leading slash" do
17
+ service = WSList.find(:get, '/services/test.xml')
18
+ service.should_not be_nil
19
+ service.url.should == '/services/test.xml'
20
+
21
+ service = WSList.find(:delete, '/services/test.xml')
22
+ service.url.should == '/services/test.xml'
23
+
24
+ service = WSList.find(:get, 'slash/foo')
25
+ service.should_not be_nil
26
+ service.url.should == "/slash/foo"
27
+ end
28
+
29
+ it "finds the root service" do
30
+ service = WSList.find(:get, '/')
31
+ service.should_not be_nil
32
+ service.extra["name"].should == "root"
33
+ end
34
+
35
+
36
+ it "raises an exception if a duplicate service is added" do
37
+ lambda{ WSList.add(WeaselDiesel.new("/")) }.should raise_exception(WSList::DuplicateServiceDescription)
38
+ end
39
+
16
40
  end
@@ -12,7 +12,7 @@ describe "Hello World example" do
12
12
  WSList.all.clear
13
13
  require "hello_world_service"
14
14
  require "hello_world_controller"
15
- @service = WSList.all.find{|s| s.url == 'hello_world.xml'}
15
+ @service = WSList.find(:get, 'hello_world.xml')
16
16
  @service.should_not be_nil
17
17
  @service.load_sinatra_route
18
18
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: weasel_diesel
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.4
4
+ version: 1.2.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-10-22 00:00:00.000000000 Z
12
+ date: 2012-10-26 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rspec
@@ -100,6 +100,7 @@ extra_rdoc_files: []
100
100
  files:
101
101
  - .gitignore
102
102
  - .travis.yml
103
+ - CHANGELOG.md
103
104
  - Gemfile
104
105
  - LICENSE
105
106
  - README.md
@@ -109,6 +110,7 @@ files:
109
110
  - lib/framework_ext/sinatra_controller.rb
110
111
  - lib/inflection.rb
111
112
  - lib/json_response_verification.rb
113
+ - lib/kernel_ext.rb
112
114
  - lib/params.rb
113
115
  - lib/params_verification.rb
114
116
  - lib/response.rb
@@ -144,7 +146,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
144
146
  version: '0'
145
147
  segments:
146
148
  - 0
147
- hash: 1819885945889786585
149
+ hash: -2531016401630925863
148
150
  required_rubygems_version: !ruby/object:Gem::Requirement
149
151
  none: false
150
152
  requirements:
@@ -153,7 +155,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
153
155
  version: '0'
154
156
  segments:
155
157
  - 0
156
- hash: 1819885945889786585
158
+ hash: -2531016401630925863
157
159
  requirements: []
158
160
  rubyforge_project: wsdsl
159
161
  rubygems_version: 1.8.24