bradphelan-sinatras-hat 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +4 -0
- data/LICENSE +22 -0
- data/README.md +235 -0
- data/Rakefile +59 -0
- data/VERSION +1 -0
- data/bradphelan-sinatras-hat.gemspec +145 -0
- data/ci.rb +9 -0
- data/example/app-with-auth.rb +14 -0
- data/example/app-with-cache.rb +30 -0
- data/example/app.rb +23 -0
- data/example/lib/comment.rb +13 -0
- data/example/lib/common.rb +19 -0
- data/example/lib/post.rb +16 -0
- data/example/simple-app.rb +4 -0
- data/example/views/comments/index.erb +6 -0
- data/example/views/comments/show.erb +1 -0
- data/example/views/posts/index.erb +8 -0
- data/example/views/posts/new.erb +11 -0
- data/example/views/posts/show.erb +28 -0
- data/features/authenticated.feature +12 -0
- data/features/create.feature +16 -0
- data/features/destroy.feature +18 -0
- data/features/edit.feature +17 -0
- data/features/formats.feature +19 -0
- data/features/headers.feature +28 -0
- data/features/index.feature +23 -0
- data/features/layouts.feature +11 -0
- data/features/nested.feature +20 -0
- data/features/new.feature +20 -0
- data/features/only.feature +13 -0
- data/features/show.feature +31 -0
- data/features/steps/authenticated_steps.rb +10 -0
- data/features/steps/common_steps.rb +77 -0
- data/features/steps/create_steps.rb +21 -0
- data/features/steps/destroy_steps.rb +16 -0
- data/features/steps/edit_steps.rb +7 -0
- data/features/steps/format_steps.rb +11 -0
- data/features/steps/header_steps.rb +7 -0
- data/features/steps/index_steps.rb +26 -0
- data/features/steps/nested_steps.rb +11 -0
- data/features/steps/new_steps.rb +15 -0
- data/features/steps/only_steps.rb +10 -0
- data/features/steps/show_steps.rb +24 -0
- data/features/steps/update_steps.rb +22 -0
- data/features/support/env.rb +17 -0
- data/features/support/views/comments/index.erb +5 -0
- data/features/support/views/layout.erb +9 -0
- data/features/support/views/people/edit.erb +1 -0
- data/features/support/views/people/index.erb +1 -0
- data/features/support/views/people/layout.erb +9 -0
- data/features/support/views/people/new.erb +1 -0
- data/features/support/views/people/show.erb +1 -0
- data/features/update.feature +25 -0
- data/lib/core_ext/array.rb +5 -0
- data/lib/core_ext/hash.rb +23 -0
- data/lib/core_ext/module.rb +14 -0
- data/lib/core_ext/object.rb +45 -0
- data/lib/sinatras-hat.rb +22 -0
- data/lib/sinatras-hat/actions.rb +81 -0
- data/lib/sinatras-hat/authentication.rb +55 -0
- data/lib/sinatras-hat/extendor.rb +24 -0
- data/lib/sinatras-hat/hash_mutator.rb +18 -0
- data/lib/sinatras-hat/logger.rb +36 -0
- data/lib/sinatras-hat/maker.rb +187 -0
- data/lib/sinatras-hat/model.rb +110 -0
- data/lib/sinatras-hat/resource.rb +57 -0
- data/lib/sinatras-hat/responder.rb +106 -0
- data/lib/sinatras-hat/response.rb +60 -0
- data/lib/sinatras-hat/router.rb +46 -0
- data/sinatras-hat.gemspec +34 -0
- data/spec/actions/create_spec.rb +68 -0
- data/spec/actions/destroy_spec.rb +58 -0
- data/spec/actions/edit_spec.rb +52 -0
- data/spec/actions/index_spec.rb +72 -0
- data/spec/actions/new_spec.rb +39 -0
- data/spec/actions/show_spec.rb +85 -0
- data/spec/actions/update_spec.rb +83 -0
- data/spec/extendor_spec.rb +78 -0
- data/spec/fixtures/views/articles/edit.erb +1 -0
- data/spec/fixtures/views/articles/index.erb +1 -0
- data/spec/fixtures/views/articles/new.erb +1 -0
- data/spec/fixtures/views/articles/show.erb +1 -0
- data/spec/hash_mutator_spec.rb +23 -0
- data/spec/maker_spec.rb +411 -0
- data/spec/model_spec.rb +152 -0
- data/spec/resource_spec.rb +74 -0
- data/spec/responder_spec.rb +139 -0
- data/spec/response_spec.rb +120 -0
- data/spec/router_spec.rb +105 -0
- data/spec/spec_helper.rb +80 -0
- metadata +161 -0
@@ -0,0 +1,77 @@
|
|
1
|
+
Before do
|
2
|
+
build_model(:people) do
|
3
|
+
string :name
|
4
|
+
timestamps
|
5
|
+
|
6
|
+
has_many :comments
|
7
|
+
|
8
|
+
validates_presence_of :name
|
9
|
+
end
|
10
|
+
|
11
|
+
build_model(:comments) do
|
12
|
+
integer :person_id
|
13
|
+
string :name
|
14
|
+
timestamps
|
15
|
+
|
16
|
+
belongs_to :person
|
17
|
+
end
|
18
|
+
|
19
|
+
Person.delete_all
|
20
|
+
Comment.delete_all
|
21
|
+
end
|
22
|
+
|
23
|
+
Given /^a model that has a record$/ do
|
24
|
+
@record = Person.create! :name => "Pat"
|
25
|
+
end
|
26
|
+
|
27
|
+
Given /^the record has children$/ do
|
28
|
+
@not_a_child = Comment.create! :name => "I should never show up!"
|
29
|
+
@child_record = @record.comments.create! :name => "Commented!"
|
30
|
+
end
|
31
|
+
|
32
|
+
Given /^a model that does not have a record$/ do
|
33
|
+
Person.all.should be_empty
|
34
|
+
@record = Person.new
|
35
|
+
class << @record
|
36
|
+
def to_param
|
37
|
+
"230934509834"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
Given /^a mounted model$/ do
|
43
|
+
mock_app do
|
44
|
+
set :views, File.join(File.dirname(__FILE__), '..', 'support', 'views')
|
45
|
+
# set :logging, true
|
46
|
+
|
47
|
+
mount Person do
|
48
|
+
mount Comment
|
49
|
+
|
50
|
+
formats[:ruby] = proc { |data| data.inspect }
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
Given /^I mount the model$/ do
|
56
|
+
Given "a mounted model"
|
57
|
+
end
|
58
|
+
|
59
|
+
When /^I make a GET request for that record$/ do
|
60
|
+
get "/people/#{@record.to_param}"
|
61
|
+
end
|
62
|
+
|
63
|
+
When /^I make a GET request for that record using the '(\w+)' format$/ do |format|
|
64
|
+
get "/people/#{@record.to_param}.#{format}"
|
65
|
+
end
|
66
|
+
|
67
|
+
Then /^the body is empty$/ do
|
68
|
+
body.should be_empty
|
69
|
+
end
|
70
|
+
|
71
|
+
Then /^the status code is (\d+)$/ do |code|
|
72
|
+
response.status.should == code.to_i
|
73
|
+
end
|
74
|
+
|
75
|
+
Then /^I should see "(.*)"$/ do |text|
|
76
|
+
body.should =~ /#{text}/
|
77
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
When /^I make a POST request with valid form params$/ do
|
2
|
+
post "/people?person[name]=Pat"
|
3
|
+
end
|
4
|
+
|
5
|
+
When /^I make a POST request with invalid form params$/ do
|
6
|
+
post "/people?person[name]="
|
7
|
+
end
|
8
|
+
|
9
|
+
# When /^I make a POST request with valid serialized attributes for a valid format$/ do
|
10
|
+
# post "/people.xml", ({:person => { :name => "Pat" }}).to_xml
|
11
|
+
# end
|
12
|
+
|
13
|
+
Then /^a record is created$/ do
|
14
|
+
@record = Person.find_by_name("Pat")
|
15
|
+
@record.should_not be_nil
|
16
|
+
end
|
17
|
+
|
18
|
+
Then /^a record is not created$/ do
|
19
|
+
@record = Person.find_by_name("Pat")
|
20
|
+
@record.should be_nil
|
21
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
When /^I make a DELETE request to the path for that record$/ do
|
2
|
+
delete "/people/#{@record.to_param}"
|
3
|
+
end
|
4
|
+
|
5
|
+
When /^I make a DELETE request to a path for a non\-existent record$/ do
|
6
|
+
delete "/people/345345435"
|
7
|
+
end
|
8
|
+
|
9
|
+
Then /^the record gets destroyed$/ do
|
10
|
+
Person.find_by_id(@record.id).should be_nil
|
11
|
+
end
|
12
|
+
|
13
|
+
Then /^I am redirected to the index action$/ do
|
14
|
+
response.status.should == 302
|
15
|
+
response.location.should == '/people'
|
16
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
Given /^specify a custom 'ruby' formatter$/ do
|
2
|
+
# this is implemented in common_steps.rb
|
3
|
+
end
|
4
|
+
|
5
|
+
Then /^the body is the custom serialized record$/ do
|
6
|
+
@response.body.should == @record.inspect
|
7
|
+
end
|
8
|
+
|
9
|
+
Then /^the result should be custom serialized$/ do
|
10
|
+
@response.body.should == Person.all.inspect
|
11
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# TODO Use acts_as_fu to build some actual models to test
|
2
|
+
|
3
|
+
Given /^the model has some records$/ do
|
4
|
+
@record = Person.create :name => "Pat"
|
5
|
+
@frank = Person.create :name => "Frank"
|
6
|
+
end
|
7
|
+
|
8
|
+
When /^Make a GET request to the index without a format$/ do
|
9
|
+
get '/people'
|
10
|
+
end
|
11
|
+
|
12
|
+
When /^Make a GET request to the index with a known format$/ do
|
13
|
+
get '/people.xml'
|
14
|
+
end
|
15
|
+
|
16
|
+
When /^Make a GET request to the index using the '(\w+)' format$/ do |format|
|
17
|
+
get "/people.#{format}"
|
18
|
+
end
|
19
|
+
|
20
|
+
When /^I make a GET request to the index with an unknown format$/ do
|
21
|
+
get '/people.say_wha'
|
22
|
+
end
|
23
|
+
|
24
|
+
Then /^the result should be serialized$/ do
|
25
|
+
@response.body.should == Person.all.to_xml
|
26
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
When /^Make a GET request to the nested index without a format$/ do
|
2
|
+
get "/people/#{@record.id}/comments"
|
3
|
+
end
|
4
|
+
|
5
|
+
When /^Make a GET request to the nested index with a valid format$/ do
|
6
|
+
get "/people/#{@record.id}/comments.xml"
|
7
|
+
end
|
8
|
+
|
9
|
+
Then /^the body is the serialized list of children$/ do
|
10
|
+
@response.body.should == @record.comments.to_xml
|
11
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
When /^I get the new page for that record$/ do
|
2
|
+
get '/people/new'
|
3
|
+
end
|
4
|
+
|
5
|
+
When /^I get the new action with a valid format$/ do
|
6
|
+
get '/people/new.xml'
|
7
|
+
end
|
8
|
+
|
9
|
+
When /^I get the new action with an invalid format$/ do
|
10
|
+
get '/people/new.oops'
|
11
|
+
end
|
12
|
+
|
13
|
+
Then /^the body is a serialized new record$/ do
|
14
|
+
body.should == Person.new.to_xml
|
15
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# TODO Use acts_as_fu to build some actual models to test
|
2
|
+
|
3
|
+
When /^I get the show page for that record$/ do
|
4
|
+
get "/people/#{@record.to_param}"
|
5
|
+
end
|
6
|
+
|
7
|
+
When /^I get the show page for the non\-existent record$/ do
|
8
|
+
get "/people/87345873485763485"
|
9
|
+
end
|
10
|
+
|
11
|
+
When /^I make a request for that record with a format$/ do
|
12
|
+
get "/people/#{@record.to_param}.xml"
|
13
|
+
end
|
14
|
+
|
15
|
+
When /^I get the GET request for a non\-existent record with a format$/ do
|
16
|
+
get "/people/87345873485763485.xml"
|
17
|
+
end
|
18
|
+
|
19
|
+
Then /^the body is the serialized record$/ do
|
20
|
+
body.should == @record.to_xml
|
21
|
+
end
|
22
|
+
|
23
|
+
# Then /^the body is the custom serialized record$/ do
|
24
|
+
# end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
When /^I make a put request with valid form params$/ do
|
2
|
+
put "/people/#{@record.to_param}?person[name]=UPDATED"
|
3
|
+
end
|
4
|
+
|
5
|
+
When /^I make a PUT request with invalid form params$/ do
|
6
|
+
put "/people/#{@record.to_param}?person[name]="
|
7
|
+
end
|
8
|
+
|
9
|
+
Then /^the record is updated$/ do
|
10
|
+
@record.reload
|
11
|
+
@record.name.should == "UPDATED"
|
12
|
+
end
|
13
|
+
|
14
|
+
Then /^the response redirects to the record show page$/ do
|
15
|
+
response.status.should == 302
|
16
|
+
response.location.should == "/people/#{@record.to_param}"
|
17
|
+
end
|
18
|
+
|
19
|
+
Then /^the record is not updated$/ do
|
20
|
+
@record.reload
|
21
|
+
@record.name.should == "Pat"
|
22
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), *%w[.. .. lib sinatras-hat])
|
2
|
+
|
3
|
+
require 'sinatra/test'
|
4
|
+
require 'acts_as_fu'
|
5
|
+
|
6
|
+
Sinatra::Test.module_eval do
|
7
|
+
def mock_app(base=Sinatra::Base, &block)
|
8
|
+
@app = Sinatra.new(base, &block)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
World do
|
13
|
+
extend ActsAsFu
|
14
|
+
extend Sinatra::Test
|
15
|
+
end
|
16
|
+
|
17
|
+
require 'spec/expectations'
|
@@ -0,0 +1 @@
|
|
1
|
+
Editing person with id: <%= @person.id %>.
|
@@ -0,0 +1 @@
|
|
1
|
+
The people: <%= @people.map(&:name).join(', ') %>.
|
@@ -0,0 +1 @@
|
|
1
|
+
So, you want to create a new <%= @person.class.name %>?
|
@@ -0,0 +1 @@
|
|
1
|
+
The person: <%= @person.name %>.
|
@@ -0,0 +1,25 @@
|
|
1
|
+
Feature: Generating an "update" action
|
2
|
+
As a developer
|
3
|
+
I want to generate an "update" action
|
4
|
+
So that I don't have to manually code it
|
5
|
+
|
6
|
+
Scenario: A PUT request with valid form params and no format
|
7
|
+
Given a model that has a record
|
8
|
+
And I mount the model
|
9
|
+
When I make a put request with valid form params
|
10
|
+
Then the record is updated
|
11
|
+
And the response redirects to the record show page
|
12
|
+
|
13
|
+
Scenario: A PUT request with invalid form params and no format
|
14
|
+
Given a model that has a record
|
15
|
+
And I mount the model
|
16
|
+
When I make a PUT request with invalid form params
|
17
|
+
Then I should see "Editing"
|
18
|
+
And the record is not updated
|
19
|
+
|
20
|
+
Scenario: Trying to update a record that does not exist
|
21
|
+
Given a model that does not have a record
|
22
|
+
And I mount the model
|
23
|
+
When I make a put request with valid form params
|
24
|
+
Then the status code is 404
|
25
|
+
And the body is empty
|
@@ -0,0 +1,23 @@
|
|
1
|
+
class Hash
|
2
|
+
def make_indifferent!
|
3
|
+
keys_values = self.dup
|
4
|
+
replace(Hash.new { |h,k| h[k.to_s] if Symbol === k })
|
5
|
+
merge!(keys_values)
|
6
|
+
end
|
7
|
+
|
8
|
+
def nest!
|
9
|
+
new_params = Hash.new.make_indifferent!
|
10
|
+
each_pair do |full_key, value|
|
11
|
+
this_param = new_params
|
12
|
+
split_keys = full_key.to_s.split(/\]\[|\]|\[/)
|
13
|
+
split_keys.each_index do |index|
|
14
|
+
break if split_keys.length == index + 1
|
15
|
+
this_param[split_keys[index]] ||= Hash.new.make_indifferent!
|
16
|
+
this_param = this_param[split_keys[index]]
|
17
|
+
end
|
18
|
+
this_param[split_keys.last] = value
|
19
|
+
end
|
20
|
+
clear
|
21
|
+
replace(new_params)
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
class Module
|
2
|
+
def delegate(*methods)
|
3
|
+
options = methods.pop
|
4
|
+
raise ArgumentError, "Delegation needs a target." unless options.is_a?(Hash) && to = options[:to]
|
5
|
+
|
6
|
+
methods.each do |method|
|
7
|
+
module_eval(<<-EOS, "(__DELEGATION__)", 1)
|
8
|
+
def #{method}(*args, &block)
|
9
|
+
#{to}.__send__(#{method.inspect}, *args, &block)
|
10
|
+
end
|
11
|
+
EOS
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'metaid'
|
2
|
+
|
3
|
+
class Object
|
4
|
+
def tap
|
5
|
+
yield self
|
6
|
+
self
|
7
|
+
end
|
8
|
+
|
9
|
+
def with(hash)
|
10
|
+
hash.each do |key, value|
|
11
|
+
meta_def(key) { hash[key] } unless respond_to?(key)
|
12
|
+
meta_def("#{key}=") { |v| hash[key] = v } unless respond_to?("#{key}=")
|
13
|
+
end
|
14
|
+
|
15
|
+
return unless block_given?
|
16
|
+
|
17
|
+
result = yield
|
18
|
+
|
19
|
+
hash.each do |key, value|
|
20
|
+
meta_eval { remove_method(key) }
|
21
|
+
meta_eval { remove_method("#{key}=") }
|
22
|
+
end
|
23
|
+
|
24
|
+
result
|
25
|
+
end
|
26
|
+
|
27
|
+
module InstanceExecHelper; end
|
28
|
+
include InstanceExecHelper
|
29
|
+
def instance_exec(*args, &block)
|
30
|
+
begin
|
31
|
+
old_critical, Thread.critical = Thread.critical, true
|
32
|
+
n = 0
|
33
|
+
n += 1 while respond_to?(mname="__instance_exec#{n}")
|
34
|
+
InstanceExecHelper.module_eval{ define_method(mname, &block) }
|
35
|
+
ensure
|
36
|
+
Thread.critical = old_critical
|
37
|
+
end
|
38
|
+
begin
|
39
|
+
ret = send(mname, *args)
|
40
|
+
ensure
|
41
|
+
InstanceExecHelper.module_eval{ remove_method(mname) } rescue nil
|
42
|
+
end
|
43
|
+
ret
|
44
|
+
end
|
45
|
+
end
|