Reputation: 786
I'm new to TDD, and I'm trying to write methods to generate URLs on a per-class basis that inherit from a parent class using Sinatra and the Namespace library in Sinatra-Contrib. I'm not too far along, because I've gotten a failed RSpec test that has kept me from moving further: undefined method 'namespace'. Can anyone help?
Gemfile:
source 'https://rubygems.org'
ruby '1.9.3'
gem 'sinatra'
gem 'sinatra-contrib'
gem 'rack'
gem 'thin'
group :development, :test do
gem 'rspec'
gem 'rack-test'
gem 'ZenTest'
gem 'autotest-growl'
gem 'autotest-fsevent'
end
base_model.rb:
require 'sinatra'
require 'sinatra/namespace'
require 'rack'
def generate_routes_for_model(model_class, rootUrl)
namespace rootUrl do
get '/show' do
"I'm the model's show route"
end
end
end
base_model_spec.rb
require_relative '../base_model.rb'
require 'rack/test'
set :environment, :test
class Foo
end
def app
Sinatra::Application
end
include Rack::Test::Methods
describe 'Create Routes for test Class' do
it "should load foo.show" do
generate_routes_for_model(Foo, '/foo')
get '/foo/show'
last_response.should be_ok
end
end
Here's the result of the test:
Failures:
1) Create Routes for test Class should load foo.show
Failure/Error: generate_routes_for_model(Foo, '/foo')
NoMethodError:
undefined method `namespace' for #<RSpec::Core::ExampleGroup::Nested_2:0x007f8571102e00>
# ./base_model.rb:16:in `generate_routes_for_model'
# ./spec/base_model_spec.rb:24:in `block (2 levels) in <top (required)>'
Upvotes: 1
Views: 1219
Reputation: 12251
It appears to be a scope problem, on first look. namespace
is a class method of a Sinatra extension (which is why you call it within the class
definition and not inside an instance method).
When you run RSpec, is namespace
ever within a class that inherits from Sinatra::Base
? I don't think so. You need to provide a Sinatra class that namespace
can run within. e.g.
class Foo; end
app = Sinatra.new do
register Sinatra::Namespace
end
def generate_routes_for_model(app_class, model_class, rootUrl)
['show'].each do |route|
app_class.namespace rootUrl do
get route do
"I'm the model's show route"
end
end
end
end
generate_routes_for_model app, Foo, "/"
app.run!
Then going to http://localhost:4567/show
will respond with "I'm the model's show route".
Or perhaps use class_eval
to define the code, there's a few ways you could tackle this, main thing to keep in mind is make sure the scope is right or the app or RSpec etc won't be able to find the method.
Edit:
Also, I'd move the generation into a before
block, as it's set up for an integration test (you're essentially saying "If the route exists then the generation worked, I don't need to test the method here", so it's a black box test of the public API - an integration test by any other name:) If you wanted to test the method itself that would be a unit test, and you'd need to look into the app
to see the routes had been generated.
describe 'Create Routes for test Class' do
before do
generate_routes_for_model(Foo, '/foo')
get '/foo/show' # this, too, is not a test but a pre-requisite for the test
end
it "should load foo.show" do
last_response.should be_ok
end
end
Upvotes: 1