Skip to content
Browse files

version bump after a few changes to the way urls are stored in the se…

…rvices, see changelog for 1.2.0 for more info
  • Loading branch information...
1 parent 4336337 commit 474305bc91e5623f983b59624bcc4919422e1b04 @mattetti committed
View
20 CHANGELOG.md
@@ -0,0 +1,20 @@
+# WeaselDiesel Changelog
+
+All changes can be seen on GitHub and git tags are used to isolate each
+release.
+
+**1.2.0**:
+
+* All service urls are now stored with a prepended slash (if not defined
+ with one). `WDList.find(<verb>, <url>)` will automatically find the
+right url even if the passed url doesn't start by a '/'. This should be
+backward compatible with most code out there as long as your code
+doesn't do a direct lookup on the url.
+The reason for this change is that I think I made a design mistake when
+I decided to define urls without a leading '/'. Sinatra and many other
+frameworks use that leading slash and it makes sense to do the same.
+
+* Adding a duplicate service (same url and verb) now raises an exception
+ instead of silently ignoring the duplicate.
+
+* Upgraded test suite to properly use `WDList.find`.
View
8 README.md
@@ -16,9 +16,9 @@ you can fork and use as a base for your application.
DSL examples:
``` ruby
-describe_service "hello_world" do |service|
+describe_service "/hello_world" do |service|
service.formats :json
- service.http_verb :get
+ service.http_verb :get # default verb, can be ommitted.
service.disable_auth # on by default
# INPUT
@@ -52,7 +52,7 @@ Or a more complex example using XML:
``` ruby
SpecOptions = ['RSpec', 'Bacon'] # usually pulled from a model
- describe_service "wsdsl/test.xml" do |service|
+ describe_service "/wsdsl/test.xml" do |service|
service.formats :xml, :json
service.http_verb :get
@@ -262,7 +262,7 @@ Consider the following JSON response:
It would be described as follows:
``` ruby
- describe_service "json_list" do |service|
+ describe_service "/json_list" do |service|
service.formats :json
service.response do |response|
response.array :people do |node|
View
4 lib/framework_ext/sinatra.rb
@@ -11,12 +11,12 @@ module WeaselDieselSinatraExtension
def load_sinatra_route
service = self
upcase_verb = service.verb.to_s.upcase
- puts "/#{self.url} -> #{self.controller_name}##{self.action} - (#{upcase_verb})"
+ puts "#{self.url} -> #{self.controller_name}##{self.action} - (#{upcase_verb})"
# Define the route directly to save some object allocations on the critical path
# Note that we are using a private API to define the route and that unlike sinatra usual DSL
# we do NOT define a HEAD route for every GET route.
- Sinatra::Base.send(:route, upcase_verb, "/#{self.url}") do
+ Sinatra::Base.send(:route, upcase_verb, self.url) do
service.controller_dispatch(self)
end
View
27 lib/kernel_ext.rb
@@ -0,0 +1,27 @@
+# Extending the top level module to add some helpers
+#
+# @api public
+module Kernel
+
+ # Base DSL method called to describe a service
+ #
+ # @param [String] url The url of the service to add.
+ # @yield [WeaselDiesel] The newly created service.
+ # @return [Array] The services already defined
+ # @example Describing a basic service
+ # describe_service "hello-world.xml" do |service|
+ # # describe the service
+ # end
+ #
+ # @api public
+ def describe_service(url, &block)
+ service = WeaselDiesel.new(url)
+ yield service
+
+ service.sync_input_param_doc
+ WSList.add(service)
+
+ service
+ end
+
+end
View
38 lib/weasel_diesel.rb
@@ -3,6 +3,7 @@
require File.expand_path('response', File.dirname(__FILE__))
require File.expand_path('documentation', File.dirname(__FILE__))
require File.expand_path('ws_list', File.dirname(__FILE__))
+require File.expand_path('kernel_ext', File.dirname(__FILE__))
# WeaselDiesel offers a web service DSL to define web services,
# their params, http verbs, formats expected as well as the documentation
@@ -117,14 +118,15 @@ class WeaselDiesel
# Service constructor which is usually used via {Kernel#describe_service}
#
- # @param [String] url Service's url
+ # @param [String] url Service's url ( the url will automatically be prepended a slash if it doesn't already contain one.
# @see #describe_service See how this class is usually initialized using `describe_service`
# @api public
def initialize(url)
- @url = url
+ @url = url.start_with?('/') ? url : "/#{url}"
@defined_params = WeaselDiesel::Params.new
@doc = WeaselDiesel::Documentation.new
@response = WeaselDiesel::Response.new
+ # TODO: extract to its own optional lib
if WeaselDiesel.use_controller_dispatch
@name = extract_service_root_name(url)
if WeaselDiesel.use_pluralized_controllers
@@ -135,6 +137,7 @@ def initialize(url)
end
@action = extract_service_action(url)
end
+ #
@verb = :get
@formats = []
@version = '0.1'
@@ -169,6 +172,7 @@ def self.use_pluralized_controllers=(val)
# @return [Boolean] The updated value, default to false
# @api public
# @since 0.3.0
+ # @deprecated
def self.use_controller_dispatch
@controller_dispatch
end
@@ -180,6 +184,7 @@ def self.use_controller_dispatch
# @return [Boolean] The updated value
# @api public
# @since 0.1.1
+ # @deprecated
def self.use_controller_dispatch=(val)
@controller_dispatch = val
end
@@ -192,6 +197,7 @@ def self.use_controller_dispatch=(val)
#
# @return [#to_s] The response from the controller action
# @api private
+ # @deprecated
def controller_dispatch(app)
unless @controller
klass = @controller_name.split("::")
@@ -419,31 +425,3 @@ def update_restful_action(verb)
end
-
-# Extending the top level module to add some helpers
-#
-# @api public
-module Kernel
-
- # Base DSL method called to describe a service
- #
- # @param [String] url The url of the service to add.
- # @yield [WeaselDiesel] The newly created service.
- # @return [Array] The services already defined
- # @example Describing a basic service
- # describe_service "hello-world.xml" do |service|
- # # describe the service
- # end
- #
- # @api public
- def describe_service(url, &block)
- service = WeaselDiesel.new(url)
- yield service
-
- service.sync_input_param_doc
- WSList.add(service)
-
- service
- end
-
-end
View
2 lib/weasel_diesel/version.rb
@@ -1,3 +1,3 @@
class WeaselDiesel
- VERSION = "1.1.4"
+ VERSION = "1.2.0"
end
View
13 lib/ws_list.rb
@@ -4,6 +4,7 @@
module WSList
class UnknownService < StandardError; end
+ class DuplicateServiceDescription < StandardError; end
module_function
@@ -12,10 +13,14 @@ class UnknownService < StandardError; end
#
# @param [WeaselDiesel] The service to add.
# @return [Array<WeaselDiesel>] All the added services.
+ # @raise DuplicateServiceDescription If a service is being duplicated.
# @api public
def add(service)
@list ||= []
- @list << service unless @list.find{|s| s.url == service.url && s.verb == service.verb}
+ if WSList.find(service.verb, service.url)
+ raise DuplicateServiceDescription, "A service accessible via #{service.verb} #{service.url} already exists"
+ end
+ @list << service
@list
end
@@ -34,6 +39,7 @@ def all
# @return [WeaselDiesel] The found service.
#
# @api public
+ # @deprecated
def named(name)
service = all.find{|service| service.name == name}
if service.nil?
@@ -49,6 +55,8 @@ def named(name)
# @return [Nil, WeaselDiesel] The found service.
#
# @api public
+ # @deprecated use #find instead since this method doesn't support a verb being passed
+ # and the url might or might not match depending on the leading slash.
def [](url)
@list.find{|service| service.url == url}
end
@@ -62,7 +70,8 @@ def [](url)
# @api public
def find(verb, url)
verb = verb.to_s.downcase.to_sym
- @list.find{|service| service.verb == verb && service.url == url}
+ slashed_url = url.start_with?('/') ? url : "/#{url}"
+ @list.find{|service| service.verb == verb && service.url == slashed_url}
end
View
10 spec/params_verification_spec.rb
@@ -3,7 +3,7 @@
describe ParamsVerification do
before :all do
- @service = WSList.all.find{|s| s.url == 'services/test.xml'}
+ @service = WSList.find(:get, '/services/test.xml')
@service.should_not be_nil
@valid_params = {'framework' => 'RSpec', 'version' => '1.02', 'user' => {'id' => '123', 'groups' => 'manager,developer', 'skills' => 'java,ruby'}}
end
@@ -87,7 +87,7 @@ def copy(params)
end
it "should cast a comma delimited string into an array when param marked as an array" do
- service = WSList.all.find{|s| s.url == "services/array_param.xml"}
+ service = WSList.find(:post, "/services/array_param.xml")
service.should_not be_nil
params = {'seq' => "a,b,c,d,e,g"}
validated = ParamsVerification.validate!(params, service.defined_params)
@@ -95,7 +95,7 @@ def copy(params)
end
it "should not raise an exception if a req array param doesn't contain a comma" do
- service = WSList.all.find{|s| s.url == "services/array_param.xml"}
+ service = WSList.find(:post, "/services/array_param.xml")
params = {'seq' => "a b c d e g"}
lambda{ ParamsVerification.validate!(params, service.defined_params) }.should_not raise_exception(ParamsVerification::InvalidParamType)
end
@@ -144,7 +144,7 @@ def copy(params)
lambda{ ParamsVerification.validate!(params, @service.defined_params) }.should raise_exception(ParamsVerification::InvalidParamValue)
# other service
params = {'preference' => {'region_code' => 'us', 'language_code' => 'de'}}
- service = WSList.all.find{|s| s.url == 'preferences.xml'}
+ service = WSList.find(:get, '/preferences.xml')
service.should_not be_nil
lambda{ ParamsVerification.validate!(params, service.defined_params) }.should raise_exception(ParamsVerification::InvalidParamValue)
end
@@ -158,7 +158,7 @@ def copy(params)
end
it "should validate that no params are passed when accept_no_params! is set on a service" do
- service = WSList.all.find{|s| s.url == "services/test_no_params.xml"}
+ service = WSList.find(:get, "/services/test_no_params.xml")
service.should_not be_nil
params = copy(@valid_params)
lambda{ ParamsVerification.validate!(params, service.defined_params) }.should raise_exception
View
8 spec/test_services.rb
@@ -127,3 +127,11 @@
end
end
+
+describe_service "/slash/foo" do |service|
+ service.formats :json
+end
+
+describe_service "/" do |service|
+ service.extra["name"] = "root"
+end
View
16 spec/wd_controller_dispatch_spec.rb
@@ -3,7 +3,7 @@
describe "WeaselDiesel #controller_dispatch" do
before :all do
- @service = WSList.all.find{|s| s.url == 'services/test.xml'}
+ @service = WSList.find(:get, '/services/test.xml')
@service.should_not be_nil
end
@@ -46,7 +46,7 @@ class ItemsController < ProjectsController
it "should be able to dispatch controller" do
describe_service("projects.xml") { |s| }
- service = WSList["projects.xml"]
+ service = WSList.find(:get, "projects.xml")
service.controller_dispatch("application").
should == ["application", "projects", "list"]
end
@@ -62,10 +62,10 @@ class ItemsController < ProjectsController
service.action = "list"
end
- service = WSList["project/:project_id/tasks.xml"]
+ service = WSList.find(:get, "project/:project_id/tasks.xml")
service.controller_dispatch("application").should == ["application", "project", "list"]
- service = WSList["project/:project_id/task/:task_id/items.xml"]
+ service = WSList.find(:get, "project/:project_id/task/:task_id/items.xml")
service.controller_dispatch("application").should == ["application", "project", "list"]
end
@@ -74,7 +74,7 @@ class ItemsController < ProjectsController
service.controller_name = "UnknownController"
service.action = "list"
end
- service = WSList["unknown.xml"]
+ service = WSList.find(:get, "unknown.xml")
lambda { service.controller_dispatch("application") }.
should raise_error("The UnknownController class was not found")
end
@@ -87,7 +87,7 @@ class ItemsController < ProjectsController
WSList.all.clear
WeaselDiesel.use_controller_dispatch = true
load File.expand_path('test_services.rb', File.dirname(__FILE__))
- @c_service = WSList.all.find{|s| s.url == 'services/test.xml'}
+ @c_service = WSList.find(:get, '/services/test.xml')
@c_service.should_not be_nil
end
after :all do
@@ -110,7 +110,7 @@ class ItemsController < ProjectsController
end
it "should support restful routes based on the HTTP verb" do
- service = WSList.all.find{|s| s.url == "services.xml"}
+ service = WSList.find(:put, "/services.xml")
service.should_not be_nil
service.http_verb.should == :put
service.action.should_not be_nil
@@ -151,7 +151,7 @@ class ItemsController < ProjectsController
service.controller_name = "CustomController"
service.action = "foo"
end
- service = WSList.all.find{|s| s.url == "players/:id.xml"}
+ service = WSList.find(:get, "players/:id.xml")
service.controller_name.should == "CustomController"
service.action.should == "foo"
end
View
8 spec/wd_documentation_spec.rb
@@ -3,7 +3,7 @@
describe WeaselDiesel::Documentation do
before :all do
- @service = WSList.all.find{|s| s.url == 'services/test.xml'}
+ @service = WSList.find(:get, '/services/test.xml')
@service.should_not be_nil
@doc = @service.doc
@doc.should_not be_nil
@@ -31,7 +31,7 @@
end
it "should allow to define namespaced params doc" do
- service = WSList.all.find{|s| s.url == "services.xml"}
+ service = WSList.find(:put, "/services.xml")
service.documentation do |doc|
doc.namespace :preference do |ns|
ns.param :id, "Ze id."
@@ -44,7 +44,7 @@
end
it "should allow object to be an alias for namespace params" do
- service = WSList.all.find{|s| s.url == "services.xml"}
+ service = WSList.find(:put, "/services.xml")
service.documentation do |doc|
doc.object :preference do |ns|
ns.param :id, "Ze id."
@@ -149,7 +149,7 @@ def define_service
end
it "should have the param documented" do
- service = WSList["legacy_param_doc"]
+ service = WSList.find(:get, "legacy_param_doc")
service.doc.params_doc.keys.sort.should == [:framework, :version]
service.doc.params_doc[service.doc.params_doc.keys.first].should_not be_nil
end
View
6 spec/wd_params_spec.rb
@@ -3,7 +3,7 @@
describe WeaselDiesel::Params do
before :all do
- @service = WSList.all.find{|s| s.url == 'services/test.xml'}
+ @service = WSList.find(:get, '/services/test.xml')
@service.should_not be_nil
@sparams = @service.params
end
@@ -31,7 +31,7 @@
end
it "should allow to define namespaced param" do
- service = WSList.all.find{|s| s.url == "services.xml"}
+ service = WSList.find(:put, "/services.xml")
service.params do |params|
params.namespace :preference do |ns|
ns.param :id, "Ze id."
@@ -44,7 +44,7 @@
end
it "should allow object as an alias to namespaced param" do
- service = WSList.all.find{|s| s.url == "services.xml"}
+ service = WSList.find(:put, "/services.xml")
service.params do |params|
params.object :preference do |ns|
ns.param :id, "Ze id."
View
14 spec/wd_spec.rb
@@ -3,13 +3,13 @@
describe WeaselDiesel do
before :all do
- @service = WSList.all.find{|s| s.url == 'services/test.xml'}
+ @service = WSList.find(:get, '/services/test.xml')
@service.should_not be_nil
end
it "should have an url" do
# dummy test since that's how we found the service, but oh well
- @service.url.should == 'services/test.xml'
+ @service.url.should == '/services/test.xml'
end
it "should have some http verbs defined" do
@@ -40,4 +40,14 @@
@service.doc.should be_an_instance_of(WeaselDiesel::Documentation)
end
+ it "should store urls with a leading slash" do
+ service = WeaselDiesel.new("/foo")
+ service.url.should == "/foo"
+ service.url.should == WeaselDiesel.new("foo").url
+ WeaselDiesel.new("foo").url.should_not == WeaselDiesel.new("foo/").url
+
+ root = WeaselDiesel.new("/")
+ root.url.should == "/"
+ end
+
end
View
30 spec/ws_list_spec.rb
@@ -5,12 +5,36 @@
it "find service by verb/route" do
service = WSList.find(:get, 'services/test.xml')
service.should_not be_nil
-
- service.url.should == 'services/test.xml'
+ service.url.should == '/services/test.xml'
service.verb.should == :get
service = WSList.find(:delete, 'services/test.xml')
- service.url.should == 'services/test.xml'
+ service.url.should == '/services/test.xml'
service.verb.should == :delete
end
+
+ it "finds service without or without the leading slash" do
+ service = WSList.find(:get, '/services/test.xml')
+ service.should_not be_nil
+ service.url.should == '/services/test.xml'
+
+ service = WSList.find(:delete, '/services/test.xml')
+ service.url.should == '/services/test.xml'
+
+ service = WSList.find(:get, 'slash/foo')
+ service.should_not be_nil
+ service.url.should == "/slash/foo"
+ end
+
+ it "finds the root service" do
+ service = WSList.find(:get, '/')
+ service.should_not be_nil
+ service.extra["name"].should == "root"
+ end
+
+
+ it "raises an exception if a duplicate service is added" do
+ lambda{ WSList.add(WeaselDiesel.new("/")) }.should raise_exception(WSList::DuplicateServiceDescription)
+ end
+
end
View
2 spec/wsdsl_sinatra_ext_spec.rb
@@ -12,7 +12,7 @@
WSList.all.clear
require "hello_world_service"
require "hello_world_controller"
- @service = WSList.all.find{|s| s.url == 'hello_world.xml'}
+ @service = WSList.find(:get, 'hello_world.xml')
@service.should_not be_nil
@service.load_sinatra_route
end

0 comments on commit 474305b

Please sign in to comment.
Something went wrong with that request. Please try again.