weasel_diesel 1.1.4 → 1.2.0

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