happy 0.1.0.pre.3 → 0.1.0.pre.4
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.
- data/happy.gemspec +1 -1
- data/lib/happy/context_ext/helpers.rb +1 -0
- data/lib/happy/controller.rb +1 -1
- data/lib/happy/controller_ext/actions.rb +15 -9
- data/lib/happy/controller_ext/routing.rb +15 -7
- data/lib/happy/ext/resources.rb +2 -2
- data/lib/happy/version.rb +1 -1
- data/spec/controller_ext/actions_spec.rb +92 -0
- data/spec/controller_ext/routing_spec.rb +63 -0
- data/spec/controller_spec.rb +14 -18
- data/spec/spec_helper.rb +20 -0
- metadata +25 -21
data/happy.gemspec
CHANGED
@@ -17,7 +17,7 @@ Gem::Specification.new do |gem|
|
|
17
17
|
|
18
18
|
gem.add_dependency 'activesupport', '~> 3.1'
|
19
19
|
gem.add_dependency 'rack', '~> 1.4'
|
20
|
-
gem.add_dependency 'happy-helpers'
|
20
|
+
gem.add_dependency 'happy-helpers', '~> 0.1.0.pre.5'
|
21
21
|
gem.add_dependency 'allowance', '>= 0.1.1'
|
22
22
|
|
23
23
|
gem.add_development_dependency 'rake'
|
data/lib/happy/controller.rb
CHANGED
@@ -10,16 +10,21 @@ module Happy
|
|
10
10
|
|
11
11
|
# Mix in default options
|
12
12
|
options = {
|
13
|
-
layout
|
13
|
+
:layout => context.layout
|
14
14
|
}.merge(options)
|
15
15
|
|
16
|
-
# Add
|
17
|
-
response.status = options
|
18
|
-
|
16
|
+
# Add status code from options
|
17
|
+
response.status = options.delete(:status) if options.has_key?(:status)
|
18
|
+
|
19
|
+
# Extract layout
|
20
|
+
layout = options.delete(:layout)
|
21
|
+
|
22
|
+
# Treat remaining options as headers
|
23
|
+
options.each { |k, v| header k, v }
|
19
24
|
|
20
25
|
# Apply layout, if available
|
21
|
-
if
|
22
|
-
data = render(
|
26
|
+
if layout
|
27
|
+
data = render(layout) { data }
|
23
28
|
end
|
24
29
|
|
25
30
|
# Set response body and finish request
|
@@ -32,7 +37,7 @@ module Happy
|
|
32
37
|
end
|
33
38
|
|
34
39
|
def redirect!(to, status = 302)
|
35
|
-
header
|
40
|
+
header :location, url_for(to)
|
36
41
|
response.status = status
|
37
42
|
halt!
|
38
43
|
end
|
@@ -42,7 +47,7 @@ module Happy
|
|
42
47
|
end
|
43
48
|
|
44
49
|
def content_type(type)
|
45
|
-
header
|
50
|
+
header :content_type, type
|
46
51
|
end
|
47
52
|
|
48
53
|
def max_age(t, options = {})
|
@@ -60,10 +65,11 @@ module Happy
|
|
60
65
|
end
|
61
66
|
|
62
67
|
def cache_control(s)
|
63
|
-
header
|
68
|
+
header :cache_control, s
|
64
69
|
end
|
65
70
|
|
66
71
|
def header(name, value)
|
72
|
+
name = name.to_s.dasherize.humanize if name.is_a?(Symbol)
|
67
73
|
response[name] = value
|
68
74
|
end
|
69
75
|
|
@@ -2,8 +2,9 @@ module Happy
|
|
2
2
|
module ControllerExtensions
|
3
3
|
module Routing
|
4
4
|
def path_to_regexp(path)
|
5
|
-
|
6
|
-
Regexp.compile('^'+path.gsub(/\)/, ')?').gsub(/\//, '\/').gsub(/\./, '\.').gsub(/:(\w+)/, '(?<\\1>.+)')+'$')
|
5
|
+
# Since we want to be compatible with Ruby 1.8.7, we unfortunately can't use named captures like this:
|
6
|
+
# Regexp.compile('^'+path.gsub(/\)/, ')?').gsub(/\//, '\/').gsub(/\./, '\.').gsub(/:(\w+)/, '(?<\\1>.+)')+'$')
|
7
|
+
Regexp.compile('^'+path.gsub(/\)/, ')?').gsub(/\//, '\/').gsub(/\./, '\.').gsub(/:(\w+)/, '(.+)')+'$')
|
7
8
|
end
|
8
9
|
|
9
10
|
def path(*args, &blk)
|
@@ -11,18 +12,25 @@ module Happy
|
|
11
12
|
args = [nil] if args.empty?
|
12
13
|
|
13
14
|
args.each do |name|
|
15
|
+
# If a path name has been given, match it against the next request path part.
|
14
16
|
if name.present?
|
17
|
+
# convert symbols to ":foo" type string
|
18
|
+
name = ":#{name}" if name.is_a?(Symbol)
|
15
19
|
path_match = path_to_regexp(name).match(remaining_path.first)
|
16
20
|
end
|
17
21
|
|
22
|
+
# Match the request method, if specified
|
18
23
|
method_matched = [nil, request.request_method.downcase.to_sym].include?(options[:method])
|
24
|
+
|
19
25
|
path_matched = (path_match || (name.nil? && remaining_path.empty?))
|
20
26
|
|
21
27
|
# Only do something here if method and requested path both match
|
22
28
|
if path_matched && method_matched
|
23
29
|
# Transfer variables contained in path name to params hash
|
24
30
|
if path_match
|
25
|
-
|
31
|
+
name.scan(/:(\w+)/).flatten.each do |var|
|
32
|
+
request.params[var] = path_match.captures.shift
|
33
|
+
end
|
26
34
|
remaining_path.shift
|
27
35
|
end
|
28
36
|
|
@@ -35,22 +43,22 @@ module Happy
|
|
35
43
|
end
|
36
44
|
|
37
45
|
def get(*args, &blk)
|
38
|
-
args.last.is_a?(Hash) ? args.last.merge(method
|
46
|
+
args.last.is_a?(Hash) ? args.last.merge(:method => :get) : args.push(:method => :get)
|
39
47
|
path(*args, &blk)
|
40
48
|
end
|
41
49
|
|
42
50
|
def post(*args, &blk)
|
43
|
-
args.last.is_a?(Hash) ? args.last.merge(method
|
51
|
+
args.last.is_a?(Hash) ? args.last.merge(:method => :post) : args.push(:method => :post)
|
44
52
|
path(*args, &blk)
|
45
53
|
end
|
46
54
|
|
47
55
|
def put(*args, &blk)
|
48
|
-
args.last.is_a?(Hash) ? args.last.merge(method
|
56
|
+
args.last.is_a?(Hash) ? args.last.merge(:method => :put) : args.push(:method => :put)
|
49
57
|
path(*args, &blk)
|
50
58
|
end
|
51
59
|
|
52
60
|
def delete(*args, &blk)
|
53
|
-
args.last.is_a?(Hash) ? args.last.merge(method
|
61
|
+
args.last.is_a?(Hash) ? args.last.merge(:method => :delete) : args.push(:method => :delete)
|
54
62
|
path(*args, &blk)
|
55
63
|
end
|
56
64
|
end
|
data/lib/happy/ext/resources.rb
CHANGED
@@ -91,8 +91,8 @@ module Happy
|
|
91
91
|
|
92
92
|
def route
|
93
93
|
@options = {
|
94
|
-
singular_name
|
95
|
-
plural_name
|
94
|
+
:singular_name => options[:class].to_s.tableize.singularize,
|
95
|
+
:plural_name => options[:class].to_s.tableize.pluralize
|
96
96
|
}.merge(@options)
|
97
97
|
|
98
98
|
path options[:plural_name] do
|
data/lib/happy/version.rb
CHANGED
@@ -0,0 +1,92 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Happy
|
4
|
+
describe ControllerExtensions::Actions do
|
5
|
+
subject { Controller.new }
|
6
|
+
|
7
|
+
describe '#serve!' do
|
8
|
+
def app
|
9
|
+
build_controller do
|
10
|
+
path('simple') { serve! "Simple response" }
|
11
|
+
path('with_headers') { serve! "body { color: red }", :content_type => 'text/css' }
|
12
|
+
path('with_status') { serve! "Not Allowed", :status => 401 }
|
13
|
+
path('with_layout') { serve! "content", :layout => 'layout.erb' }
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
it "serves the provided string as the response body" do
|
18
|
+
response_for { get '/simple' }.body.should == 'Simple response'
|
19
|
+
end
|
20
|
+
|
21
|
+
it "responds with a status code of 200 by default" do
|
22
|
+
response_for { get '/simple' }.status.should == 200
|
23
|
+
end
|
24
|
+
|
25
|
+
it "sets the response status code to its :status option" do
|
26
|
+
response_for { get '/with_status' }.status.should == 401
|
27
|
+
end
|
28
|
+
|
29
|
+
it "uses the layout provided through the :layout option" do
|
30
|
+
instance = Controller.new
|
31
|
+
instance.send(:context).should_receive(:render).with('layout.erb')
|
32
|
+
|
33
|
+
catch(:done) { instance.serve! "content", :layout => 'layout.erb' }
|
34
|
+
end
|
35
|
+
|
36
|
+
it "sets extra options as response headers" do
|
37
|
+
response_for { get '/with_headers' }['Content-type'].should == 'text/css'
|
38
|
+
end
|
39
|
+
|
40
|
+
it "finishes the rendering by throwing :done" do
|
41
|
+
expect { subject.serve! "body" }.to throw_symbol :done
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
describe '#redirect!' do
|
46
|
+
it "triggers a redirection to the specified URL" do
|
47
|
+
def app
|
48
|
+
build_controller { redirect! 'http://www.test.com' }
|
49
|
+
end
|
50
|
+
|
51
|
+
get '/'
|
52
|
+
last_response.status.should == 302
|
53
|
+
last_response.headers['Location'].should == 'http://www.test.com'
|
54
|
+
end
|
55
|
+
|
56
|
+
it "sets the provided status code" do
|
57
|
+
def app
|
58
|
+
build_controller { redirect! 'http://www.test.com', 301 }
|
59
|
+
end
|
60
|
+
|
61
|
+
get '/'
|
62
|
+
last_response.status.should == 301
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
describe '#header' do
|
67
|
+
it "sets the specified header in the response" do
|
68
|
+
subject.send(:context).response.should_receive(:[]=).with('Content-type', 'text/css')
|
69
|
+
subject.header 'Content-type', 'text/css'
|
70
|
+
end
|
71
|
+
|
72
|
+
it "also accepts the header name as a symbol" do
|
73
|
+
subject.send(:context).response.should_receive(:[]=).with('Content-type', 'text/css')
|
74
|
+
subject.header :content_type, 'text/css'
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
describe '#content_type' do
|
79
|
+
it "sets the Content-type header" do
|
80
|
+
subject.should_receive(:header).with(:content_type, 'text/css')
|
81
|
+
subject.content_type 'text/css'
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
describe '#layout' do
|
86
|
+
it "sets the layout to be used by the current context" do
|
87
|
+
subject.send(:context).should_receive(:layout=).with('layout.erb')
|
88
|
+
subject.layout 'layout.erb'
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Happy
|
4
|
+
describe ControllerExtensions::Routing do
|
5
|
+
describe '#path' do
|
6
|
+
subject do
|
7
|
+
Controller.build do
|
8
|
+
route do
|
9
|
+
path('foo') { serve! 'bar' }
|
10
|
+
path('one', 'two') { serve! 'onetwo' }
|
11
|
+
path('hello') do
|
12
|
+
path(:name) { serve! "Hello #{params['name']}" }
|
13
|
+
serve! "Please provide a name."
|
14
|
+
end
|
15
|
+
path('number-:num') { serve! "num = #{params['num']}" }
|
16
|
+
serve! "root"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
it "routes requests to the specified path to its contained block" do
|
22
|
+
response_for { get '/' }.body.should == 'root'
|
23
|
+
response_for { get '/foo' }.body.should == 'bar'
|
24
|
+
end
|
25
|
+
|
26
|
+
it "routes independently from the request method" do
|
27
|
+
response_for { post '/foo' }.body.should == 'bar'
|
28
|
+
end
|
29
|
+
|
30
|
+
it "supports multiple path parameters" do
|
31
|
+
response_for { get '/one' }.body.should == 'onetwo'
|
32
|
+
response_for { get '/two' }.body.should == 'onetwo'
|
33
|
+
end
|
34
|
+
|
35
|
+
it "routes to the root code if no path matches" do
|
36
|
+
response_for { get '/' }.body.should == 'root'
|
37
|
+
end
|
38
|
+
|
39
|
+
it "executes the contained serve! call if no sub-paths match" do
|
40
|
+
response_for { get '/hello' }.body.should == 'Please provide a name.'
|
41
|
+
end
|
42
|
+
|
43
|
+
it "parses parameters when the provided path is a symbol" do
|
44
|
+
response_for { get '/hello/hendrik' }.body.should == 'Hello hendrik'
|
45
|
+
end
|
46
|
+
|
47
|
+
it "parses parameters within path names" do
|
48
|
+
response_for { get '/number-123' }.body.should == 'num = 123'
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
%w(get post put delete).each do |what|
|
53
|
+
describe "##{what}" do
|
54
|
+
subject { Controller.new }
|
55
|
+
|
56
|
+
it "merely invokes #path with the :method => :#{what} option" do
|
57
|
+
subject.should_receive(:path).with('path', :method => what.to_sym)
|
58
|
+
subject.send(what, 'path')
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
data/spec/controller_spec.rb
CHANGED
@@ -2,6 +2,20 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
module Happy
|
4
4
|
describe Controller do
|
5
|
+
subject do
|
6
|
+
Controller.build do
|
7
|
+
route do
|
8
|
+
serve! "it works"
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
it "is mountable as a Rack app" do
|
14
|
+
subject.should respond_to(:call)
|
15
|
+
get '/'
|
16
|
+
last_response.body.should == 'it works'
|
17
|
+
end
|
18
|
+
|
5
19
|
describe ".build" do
|
6
20
|
subject do
|
7
21
|
Controller.build do
|
@@ -9,10 +23,6 @@ module Happy
|
|
9
23
|
end
|
10
24
|
end
|
11
25
|
|
12
|
-
def app
|
13
|
-
subject
|
14
|
-
end
|
15
|
-
|
16
26
|
it "creates a new controller class" do
|
17
27
|
subject.ancestors.should include(Controller)
|
18
28
|
end
|
@@ -22,19 +32,5 @@ module Happy
|
|
22
32
|
last_response.body.should == 'yay!'
|
23
33
|
end
|
24
34
|
end
|
25
|
-
|
26
|
-
it "is also a Rack app" do
|
27
|
-
def app
|
28
|
-
Controller.build do
|
29
|
-
route do
|
30
|
-
serve! "it works"
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
get '/'
|
36
|
-
last_response.body.should == 'it works'
|
37
|
-
end
|
38
|
-
|
39
35
|
end
|
40
36
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -8,6 +8,26 @@ require 'rack/test'
|
|
8
8
|
|
9
9
|
require 'happy'
|
10
10
|
|
11
|
+
module SpecHelpers
|
12
|
+
def app
|
13
|
+
subject
|
14
|
+
end
|
15
|
+
|
16
|
+
def response_for
|
17
|
+
yield if block_given?
|
18
|
+
last_response
|
19
|
+
end
|
20
|
+
|
21
|
+
def build_controller(&blk)
|
22
|
+
Happy::Controller.build do
|
23
|
+
route do
|
24
|
+
instance_exec(&blk)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
11
30
|
RSpec.configure do |conf|
|
12
31
|
conf.include Rack::Test::Methods
|
32
|
+
conf.include SpecHelpers
|
13
33
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: happy
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.0.pre.
|
4
|
+
version: 0.1.0.pre.4
|
5
5
|
prerelease: 6
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -13,7 +13,7 @@ date: 2012-05-31 00:00:00.000000000 Z
|
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activesupport
|
16
|
-
requirement: &
|
16
|
+
requirement: &70114163872540 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ~>
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: '3.1'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *70114163872540
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: rack
|
27
|
-
requirement: &
|
27
|
+
requirement: &70114163872020 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ~>
|
@@ -32,21 +32,21 @@ dependencies:
|
|
32
32
|
version: '1.4'
|
33
33
|
type: :runtime
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *70114163872020
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: happy-helpers
|
38
|
-
requirement: &
|
38
|
+
requirement: &70114163868380 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
|
-
- -
|
41
|
+
- - ~>
|
42
42
|
- !ruby/object:Gem::Version
|
43
|
-
version:
|
43
|
+
version: 0.1.0.pre.5
|
44
44
|
type: :runtime
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *70114163868380
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: allowance
|
49
|
-
requirement: &
|
49
|
+
requirement: &70114163867700 !ruby/object:Gem::Requirement
|
50
50
|
none: false
|
51
51
|
requirements:
|
52
52
|
- - ! '>='
|
@@ -54,10 +54,10 @@ dependencies:
|
|
54
54
|
version: 0.1.1
|
55
55
|
type: :runtime
|
56
56
|
prerelease: false
|
57
|
-
version_requirements: *
|
57
|
+
version_requirements: *70114163867700
|
58
58
|
- !ruby/object:Gem::Dependency
|
59
59
|
name: rake
|
60
|
-
requirement: &
|
60
|
+
requirement: &70114163867160 !ruby/object:Gem::Requirement
|
61
61
|
none: false
|
62
62
|
requirements:
|
63
63
|
- - ! '>='
|
@@ -65,10 +65,10 @@ dependencies:
|
|
65
65
|
version: '0'
|
66
66
|
type: :development
|
67
67
|
prerelease: false
|
68
|
-
version_requirements: *
|
68
|
+
version_requirements: *70114163867160
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: rspec
|
71
|
-
requirement: &
|
71
|
+
requirement: &70114163866580 !ruby/object:Gem::Requirement
|
72
72
|
none: false
|
73
73
|
requirements:
|
74
74
|
- - ~>
|
@@ -76,10 +76,10 @@ dependencies:
|
|
76
76
|
version: '2.8'
|
77
77
|
type: :development
|
78
78
|
prerelease: false
|
79
|
-
version_requirements: *
|
79
|
+
version_requirements: *70114163866580
|
80
80
|
- !ruby/object:Gem::Dependency
|
81
81
|
name: rspec-html-matchers
|
82
|
-
requirement: &
|
82
|
+
requirement: &70114163866080 !ruby/object:Gem::Requirement
|
83
83
|
none: false
|
84
84
|
requirements:
|
85
85
|
- - ! '>='
|
@@ -87,10 +87,10 @@ dependencies:
|
|
87
87
|
version: '0'
|
88
88
|
type: :development
|
89
89
|
prerelease: false
|
90
|
-
version_requirements: *
|
90
|
+
version_requirements: *70114163866080
|
91
91
|
- !ruby/object:Gem::Dependency
|
92
92
|
name: rack-test
|
93
|
-
requirement: &
|
93
|
+
requirement: &70114163865340 !ruby/object:Gem::Requirement
|
94
94
|
none: false
|
95
95
|
requirements:
|
96
96
|
- - ! '>='
|
@@ -98,10 +98,10 @@ dependencies:
|
|
98
98
|
version: '0'
|
99
99
|
type: :development
|
100
100
|
prerelease: false
|
101
|
-
version_requirements: *
|
101
|
+
version_requirements: *70114163865340
|
102
102
|
- !ruby/object:Gem::Dependency
|
103
103
|
name: watchr
|
104
|
-
requirement: &
|
104
|
+
requirement: &70114163864500 !ruby/object:Gem::Requirement
|
105
105
|
none: false
|
106
106
|
requirements:
|
107
107
|
- - ! '>='
|
@@ -109,7 +109,7 @@ dependencies:
|
|
109
109
|
version: '0'
|
110
110
|
type: :development
|
111
111
|
prerelease: false
|
112
|
-
version_requirements: *
|
112
|
+
version_requirements: *70114163864500
|
113
113
|
description: A happy little toolkit for writing web applications.
|
114
114
|
email:
|
115
115
|
- hendrik@mans.de
|
@@ -139,6 +139,8 @@ files:
|
|
139
139
|
- lib/happy/ext/static.rb
|
140
140
|
- lib/happy/request.rb
|
141
141
|
- lib/happy/version.rb
|
142
|
+
- spec/controller_ext/actions_spec.rb
|
143
|
+
- spec/controller_ext/routing_spec.rb
|
142
144
|
- spec/controller_spec.rb
|
143
145
|
- spec/spec_helper.rb
|
144
146
|
homepage: https://github.com/hmans/happy
|
@@ -166,6 +168,8 @@ signing_key:
|
|
166
168
|
specification_version: 3
|
167
169
|
summary: A happy little toolkit for writing web applications.
|
168
170
|
test_files:
|
171
|
+
- spec/controller_ext/actions_spec.rb
|
172
|
+
- spec/controller_ext/routing_spec.rb
|
169
173
|
- spec/controller_spec.rb
|
170
174
|
- spec/spec_helper.rb
|
171
175
|
has_rdoc:
|