happy 0.1.0.pre19 → 0.1.0.pre20

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.
@@ -0,0 +1,105 @@
1
+ lib_path = File.expand_path("#{File.dirname(__FILE__)}/../lib")
2
+ $LOAD_PATH.unshift lib_path unless $LOAD_PATH.include?(lib_path)
3
+
4
+ require 'happy'
5
+ require 'cgi'
6
+
7
+ class TestApp < Happy::Controller
8
+ def examples; @examples ||= {}; end
9
+
10
+ def example(name, path_name = nil, &blk)
11
+ path_name ||= name.parameterize
12
+ examples[name] = path_name
13
+
14
+ # Create a path containing the example's code block
15
+ path(path_name, &blk)
16
+ end
17
+
18
+ def route
19
+ example 'Returning just a string' do
20
+ "I'm just a string!"
21
+ end
22
+
23
+ example 'Explicit responses' do
24
+ serve! "I was served through #serve!"
25
+ serve! "I'm not being served, since the above call to #serve! halted processing."
26
+ end
27
+
28
+ example 'Path parameters' do
29
+ path 'hello' do
30
+ path :name do
31
+ "Hello, #{params['name']}!"
32
+ end
33
+ end
34
+
35
+ "Try #{link_to 'this', current_url('hello', 'hendrik')}!"
36
+ end
37
+
38
+ example 'Inline path parameters' do
39
+ path 'hello-:name' do
40
+ "Hello, #{params['name']}!"
41
+ end
42
+
43
+ "Try #{link_to 'this', current_url('hello-hendrik')}!"
44
+ end
45
+
46
+ example 'Permissions' do
47
+ # set up permissions ;-)
48
+ can.dance!
49
+
50
+ path 'dance' do
51
+ if can.dance?
52
+ "You can dance."
53
+ else
54
+ "You can not dance."
55
+ end
56
+ end
57
+
58
+ "Can you #{link_to 'dance', current_url('dance')}?"
59
+ end
60
+
61
+ example 'Layouts' do
62
+ path 'with-layout' do
63
+ layout 'layout.erb'
64
+
65
+ path 'changed-my-mind' do
66
+ layout false
67
+ "This should render without a layout."
68
+ end
69
+
70
+ "This should render with a layout."
71
+ end
72
+
73
+ "This should render without a layout."
74
+ end
75
+
76
+ example 'Invoking other controllers' do
77
+ # creata new controller on the fly
78
+ c = Happy.route do
79
+ "Controller wrapping works, yay!"
80
+ end
81
+
82
+ # pass control over the request to that controller
83
+ run c
84
+ end
85
+
86
+ example 'Invoking Rack apps' do
87
+ # define a Rack app
88
+ rackapp = lambda { |env| [200, {'Content-type' => 'text/html'}, ["It works!"]] }
89
+
90
+ # pass control over the request to the Rack application
91
+ run rackapp
92
+ end
93
+
94
+ example 'Errors' do
95
+ null = Happy::Controller.new
96
+
97
+ # Trigger an error. This should display a nice error page.
98
+ null.foobar
99
+ end
100
+
101
+ render 'index.erb'
102
+ end
103
+ end
104
+
105
+ run TestApp
@@ -0,0 +1,7 @@
1
+ <h3>Happy Tests</h3>
2
+
3
+ <ul>
4
+ <% examples.each do |name, args| %>
5
+ <li><%= link_to name, args %></li>
6
+ <% end %>
7
+ </ul>
@@ -0,0 +1,3 @@
1
+ <h1>With Layout!</h1>
2
+
3
+ <%= yield %>
@@ -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', '~> 0.1.0.pre10'
20
+ gem.add_dependency 'happy-helpers', '~> 0.1.0.pre11'
21
21
  gem.add_dependency 'allowance', '>= 0.1.1'
22
22
 
23
23
  gem.add_dependency 'happy-cli', '>= 0.1.0.pre1'
@@ -1,7 +1,6 @@
1
1
  require 'rack'
2
2
  require 'happy/version'
3
3
  require 'happy/errors'
4
- require 'happy/context'
5
4
  require 'happy/controller'
6
5
 
7
6
  module Happy
@@ -13,22 +12,8 @@ module Happy
13
12
  # its routing block.
14
13
  #
15
14
  def self.route(&blk)
16
- @last_controller_class_created = Class.new(Happy::Controller).tap do |klass|
15
+ Class.new(Happy::Controller).tap do |klass|
17
16
  klass.send(:define_method, :route, &blk)
18
17
  end
19
18
  end
20
-
21
- # Run the provided block against Happy::Context. Use this to add new
22
- # methods to the request context class.
23
- #
24
- def self.context(&blk)
25
- Context.class_exec(&blk)
26
- end
27
-
28
- def self.call(env)
29
- @last_controller_class_created.try(:call, env) or raise "Please use Happy.route to define some routes."
30
- end
31
19
  end
32
-
33
- __END__
34
- yooooooo!
@@ -1,7 +1,13 @@
1
+ require 'happy/request'
2
+ require 'happy/response'
3
+
4
+ require 'happy/controller/helpers'
1
5
  require 'happy/controller/routing'
2
6
  require 'happy/controller/actions'
3
7
  require 'happy/controller/rackable'
4
8
  require 'happy/controller/configurable'
9
+ require 'happy/controller/cascadable'
10
+ require 'happy/controller/permissions'
5
11
 
6
12
  module Happy
7
13
  # Base class for Happy controllers. A controller's primary job is to act
@@ -14,13 +20,11 @@ module Happy
14
20
  include Actions
15
21
  include Rackable
16
22
  include Configurable
23
+ include Cascadable
24
+ include Permissions
25
+ include Helpers
17
26
 
18
- attr_reader :options, :env, :root_path
19
-
20
- delegate :request, :response, :params, :session,
21
- :previous_path, :remaining_path,
22
- :render, :url_for,
23
- :to => :context
27
+ attr_reader :options, :env, :unprocessed_path, :processed_path
24
28
 
25
29
  # Creates a new instance of {Controller}. When a block is provided,
26
30
  # it is run against the new instance, allowing custom controller classes
@@ -31,45 +35,54 @@ module Happy
31
35
  # @param options [Hash]
32
36
  # Controller options.
33
37
  #
34
- def initialize(env = {}, options = {}, &blk)
35
- @env = env
38
+ def initialize(env_or_parent = {}, options = {}, &blk)
39
+ if env_or_parent.is_a?(Happy::Controller)
40
+ @parent_controller = env_or_parent
41
+ @env = @parent_controller.env
42
+ @unprocessed_path = env_or_parent.unprocessed_path
43
+ @processed_path = env_or_parent.processed_path
44
+ else
45
+ @env = env_or_parent
46
+ @unprocessed_path = request.path.split('/').reject {|s| s.blank? }
47
+ @processed_path = []
48
+ end
49
+
36
50
  @options = options
37
51
 
38
52
  # Save a copy of the current path as this controller's root path.
39
- @root_path = context.previous_path.dup
53
+ @root_url = processed_path.join('/')
40
54
 
41
55
  # Execute block against this instance, allowing the controller to
42
56
  # provide a DSL for configuration.
43
57
  instance_exec(&blk) if blk
44
58
  end
45
59
 
46
- protected
47
-
48
- # Run this controller, performing its routing logic.
49
- #
50
- def perform
51
- context.with_controller(self) do
52
- route
53
- end
60
+ def request
61
+ @env['happy.request'] ||= Happy::Request.new(@env)
54
62
  end
55
63
 
56
- def root_url(extras = nil)
57
- url_for(root_path, extras)
64
+ def response
65
+ @env['happy.response'] ||= Happy::Response.new
58
66
  end
59
67
 
60
- private
68
+ protected
61
69
 
62
- def url(extras = nil)
63
- url_for(previous_path, extras)
70
+ def root_url(*extras)
71
+ url_for(@root_url, extras)
64
72
  end
65
73
 
66
- def context
67
- @env['happy.context'] ||= Happy::Context.new(@env)
74
+ private
75
+
76
+ def current_url(*extras)
77
+ url_for(processed_path, extras)
68
78
  end
69
79
 
70
80
  def route
71
81
  # override this in subclasses
72
82
  end
73
83
 
84
+ def params; request.params; end
85
+ def session; request.session; end
86
+
74
87
  end
75
88
  end
@@ -8,7 +8,7 @@ module Happy
8
8
 
9
9
  # Mix in default options
10
10
  options = {
11
- :layout => context.layout
11
+ :layout => response.layout
12
12
  }.merge(options)
13
13
 
14
14
  # Add status code from options
@@ -31,9 +31,9 @@ module Happy
31
31
  end
32
32
  end
33
33
 
34
- def halt!(message = :done)
34
+ def halt!(message = :done, what = nil)
35
35
  only_if_path_matches do
36
- throw message
36
+ throw message, what || response
37
37
  end
38
38
  end
39
39
 
@@ -46,7 +46,7 @@ module Happy
46
46
  end
47
47
 
48
48
  def layout(name)
49
- context.layout = name
49
+ response.layout = name
50
50
  end
51
51
 
52
52
  def content_type(type)
@@ -79,11 +79,10 @@ module Happy
79
79
  def run(thing, options = {}, &blk)
80
80
  if thing.is_a?(Class) && thing.ancestors.include?(Happy::Controller)
81
81
  # Happy controllers!
82
- thing.new(env, options, &blk).perform
82
+ thing.new(self, options, &blk).route
83
83
  elsif thing.respond_to?(:call)
84
84
  # Rack apps!
85
- context.response = thing.call(request.env)
86
- throw :done
85
+ throw :done, thing.call(request.env)
87
86
  elsif thing.respond_to?(:to_s)
88
87
  thing.to_s
89
88
  else
@@ -99,7 +98,7 @@ module Happy
99
98
  # is not the path the user requested.)
100
99
  #
101
100
  def only_if_path_matches
102
- yield if remaining_path.empty?
101
+ yield if unprocessed_path.empty?
103
102
  end
104
103
  end
105
104
  end
@@ -0,0 +1,17 @@
1
+ module Happy
2
+ class Controller
3
+ module Cascadable
4
+ def method_missing(name, *args, &blk)
5
+ if @parent_controller && @parent_controller.respond_to?(name)
6
+ @parent_controller.send(name, *args, &blk)
7
+ else
8
+ super
9
+ end
10
+ end
11
+
12
+ def respond_to?(name)
13
+ super || @parent_controller.try(:respond_to?, name)
14
+ end
15
+ end
16
+ end
17
+ end
@@ -1,7 +1,7 @@
1
1
  require 'happy-helpers'
2
2
 
3
3
  module Happy
4
- class Context
4
+ class Controller
5
5
  module Helpers
6
6
  include HappyHelpers::Helpers
7
7
 
@@ -0,0 +1,17 @@
1
+ require 'allowance'
2
+
3
+ module Happy
4
+ class Controller
5
+ module Permissions
6
+ def permissions(&blk)
7
+ (@env['happy.permissions'] ||= Allowance::Permissions.new).tap do |p|
8
+ if blk
9
+ blk.arity == 0 ? p.instance_exec(&blk) : blk.call(p)
10
+ end
11
+ end
12
+ end
13
+
14
+ alias_method :can, :permissions
15
+ end
16
+ end
17
+ end
@@ -4,19 +4,21 @@ module Happy
4
4
  extend ActiveSupport::Concern
5
5
 
6
6
  def handle_request
7
- catch :done do
8
- serve!(perform) or raise Errors::NotFound
7
+ r = catch :done do
8
+ serve!(route) or raise Errors::NotFound
9
9
  end
10
10
 
11
- response
11
+ r ||response
12
+
12
13
  rescue Errors::NotFound => e
13
- html = Errors.html e, env,
14
+ html = Errors.html e, self,
14
15
  :title => "Path not found",
15
16
  :message => '',
16
- :friendly_message => "You performed a <strong>#{context.request.request_method}</strong> request on <strong>#{context.request.path}</strong>, but your application did not know how to handle this request."
17
+ :friendly_message => "You performed a <strong>#{request.request_method}</strong> request on <strong>#{request.path}</strong>, but your application did not know how to handle this request."
17
18
  [404, {'Content-type' => 'text/html'}, [html]]
19
+
18
20
  rescue ::Exception => e
19
- html = Errors.html e, env
21
+ html = Errors.html e, self
20
22
  [500, {'Content-type' => 'text/html'}, [html]]
21
23
  end
22
24
 
@@ -16,13 +16,13 @@ module Happy
16
16
  if name.present?
17
17
  # convert symbols to ":foo" type string
18
18
  name = ":#{name}" if name.is_a?(Symbol)
19
- path_match = path_to_regexp(name).match(remaining_path.first)
19
+ path_match = path_to_regexp(name).match(unprocessed_path.first)
20
20
  end
21
21
 
22
22
  # Match the request method, if specified
23
23
  method_matched = [nil, request.request_method.downcase.to_sym].include?(options[:method])
24
24
 
25
- path_matched = (path_match || (name.nil? && remaining_path.empty?))
25
+ path_matched = (path_match || (name.nil? && unprocessed_path.empty?))
26
26
 
27
27
  # Only do something here if method and requested path both match
28
28
  if path_matched && method_matched
@@ -31,7 +31,7 @@ module Happy
31
31
  name.scan(/:(\w+)/).flatten.each do |var|
32
32
  request.params[var] = path_match.captures.shift
33
33
  end
34
- previous_path << remaining_path.shift
34
+ processed_path << unprocessed_path.shift
35
35
  end
36
36
 
37
37
  serve!(instance_exec(&blk)) or raise Errors::NotFound
@@ -18,15 +18,13 @@ module Happy
18
18
  # Friendly error message to be displayed below title and message.
19
19
  # If left blank, will be generated from the exception message.
20
20
  #
21
- def self.html(exception, env, options = {})
21
+ def self.html(exception, controller, options = {})
22
22
  options = {
23
23
  :title => exception.class.to_s,
24
24
  :message => exception.message,
25
25
  :friendly_message => nil
26
26
  }.merge(options)
27
27
 
28
- context = env['happy.context']
29
-
30
28
  # Load and cache error template.
31
29
  @html = begin
32
30
  File.read(File.expand_path(File.join(__FILE__, '../files/error.erb')))
@@ -1,5 +1,3 @@
1
- require 'happy/extras/permissions'
2
-
3
1
  module Happy
4
2
  module Extras
5
3
  module Resources
@@ -31,19 +29,19 @@ module Happy
31
29
  end
32
30
 
33
31
  def set_plural_variable(v)
34
- context.instance_variable_set "@#{options[:plural_name]}", v
32
+ instance_variable_set "@#{options[:plural_name]}", v
35
33
  end
36
34
 
37
35
  def plural_variable
38
- context.instance_variable_get "@#{options[:plural_name]}"
36
+ instance_variable_get "@#{options[:plural_name]}"
39
37
  end
40
38
 
41
39
  def set_singular_variable(v)
42
- context.instance_variable_set "@#{options[:singular_name]}", v
40
+ instance_variable_set "@#{options[:singular_name]}", v
43
41
  end
44
42
 
45
43
  def singular_variable
46
- context.instance_variable_get "@#{options[:singular_name]}"
44
+ instance_variable_get "@#{options[:singular_name]}"
47
45
  end
48
46
 
49
47
  def do_index
@@ -4,7 +4,6 @@ module Happy
4
4
  module Extras
5
5
  class Scriptable < Happy::Controller
6
6
  def route
7
- Happy::Context.class_eval(load_script 'context.rb')
8
7
  run_script 'permissions.rb'
9
8
  run_script 'route.rb'
10
9
  end
@@ -110,17 +110,17 @@
110
110
 
111
111
  <h2>Request Parameters:</h2>
112
112
  <div class="output params">
113
- <%= h context.request.params.inspect %>
113
+ <%= h controller.request.params.inspect %>
114
114
  </div>
115
115
 
116
116
  <h2>Session:</h2>
117
117
  <div class="output session">
118
- <%= h context.request.session.inspect %>
118
+ <%= h controller.request.session.inspect %>
119
119
  </div>
120
120
 
121
121
  <h2>Environment:</h2>
122
122
  <div class="output env">
123
- <%= h env %>
123
+ <%= h controller.env %>
124
124
  </div>
125
125
 
126
126
  <p>
@@ -0,0 +1,10 @@
1
+ module Happy
2
+ class Response < Rack::Response
3
+ attr_accessor :layout
4
+
5
+ def initialize(*args)
6
+ super
7
+ @layout = nil
8
+ end
9
+ end
10
+ end
@@ -1,3 +1,3 @@
1
1
  module Happy
2
- VERSION = "0.1.0.pre19"
2
+ VERSION = "0.1.0.pre20"
3
3
  end
@@ -28,7 +28,7 @@ module Happy
28
28
 
29
29
  it "uses the layout provided through the :layout option" do
30
30
  instance = Controller.new
31
- instance.send(:context).should_receive(:render).with('layout.erb')
31
+ instance.should_receive(:render).with('layout.erb')
32
32
 
33
33
  catch(:done) { instance.serve! "content", :layout => 'layout.erb' }
34
34
  end
@@ -138,12 +138,12 @@ module Happy
138
138
 
139
139
  describe '#header' do
140
140
  it "sets the specified header in the response" do
141
- subject.send(:context).response.should_receive(:[]=).with('Content-type', 'text/css')
141
+ subject.send(:response).should_receive(:[]=).with('Content-type', 'text/css')
142
142
  subject.header 'Content-type', 'text/css'
143
143
  end
144
144
 
145
145
  it "also accepts the header name as a symbol" do
146
- subject.send(:context).response.should_receive(:[]=).with('Content-type', 'text/css')
146
+ subject.send(:response).should_receive(:[]=).with('Content-type', 'text/css')
147
147
  subject.header :content_type, 'text/css'
148
148
  end
149
149
  end
@@ -157,7 +157,7 @@ module Happy
157
157
 
158
158
  describe '#layout' do
159
159
  it "sets the layout to be used by the current context" do
160
- subject.send(:context).should_receive(:layout=).with('layout.erb')
160
+ subject.send(:response).should_receive(:layout=).with('layout.erb')
161
161
  subject.layout 'layout.erb'
162
162
  end
163
163
  end
@@ -0,0 +1,43 @@
1
+ require 'spec_helper'
2
+
3
+ module Happy
4
+ describe Controller::Cascadable do
5
+
6
+ describe '#method_missing' do
7
+ it "passes on all method calls to a parent if there is one" do
8
+ class Inner < Controller
9
+ def route
10
+ path 'one' do
11
+ some_helper
12
+ end
13
+
14
+ path 'two' do
15
+ some_unknown_helper
16
+ end
17
+ end
18
+ end
19
+
20
+ class Middle < Controller
21
+ def route
22
+ run Inner
23
+ end
24
+ end
25
+
26
+ class Outer < Controller
27
+ def some_helper; 'some_information'; end
28
+ def route
29
+ run Middle
30
+ end
31
+ end
32
+
33
+ def app
34
+ Outer
35
+ end
36
+
37
+ response_for { get '/one' }.body.should == 'some_information'
38
+ response_for { get '/two' }.status.should == 500
39
+ end
40
+ end
41
+
42
+ end
43
+ end
@@ -18,19 +18,19 @@ module Happy
18
18
  last_response.body.should == 'it works'
19
19
  end
20
20
 
21
- describe '#url' do
21
+ describe '#current_url' do
22
22
  it "returns the current URL" do
23
23
  def app
24
24
  build_controller do
25
25
  path 'foo' do
26
26
  path 'bar' do
27
- "My URL is #{url}"
27
+ "My URL is #{current_url}"
28
28
  end
29
29
 
30
- "My URL is #{url}"
30
+ "My URL is #{current_url}"
31
31
  end
32
32
 
33
- "My URL is #{url}"
33
+ "My URL is #{current_url}"
34
34
  end
35
35
  end
36
36
 
@@ -43,12 +43,12 @@ module Happy
43
43
  def app
44
44
  build_controller do
45
45
  path 'foo' do
46
- url('bar')
46
+ current_url('bar', 'moo')
47
47
  end
48
48
  end
49
49
  end
50
50
 
51
- response_for { get '/foo' }.body.should == "/foo/bar"
51
+ response_for { get '/foo' }.body.should == "/foo/bar/moo"
52
52
  end
53
53
  end
54
54
 
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.pre19
4
+ version: 0.1.0.pre20
5
5
  prerelease: 6
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-06-10 00:00:00.000000000 Z
12
+ date: 2012-06-12 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activesupport
16
- requirement: &70302468087940 !ruby/object:Gem::Requirement
16
+ requirement: &70246363046260 !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: *70302468087940
24
+ version_requirements: *70246363046260
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: rack
27
- requirement: &70302468086760 !ruby/object:Gem::Requirement
27
+ requirement: &70246363043080 !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: *70302468086760
35
+ version_requirements: *70246363043080
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: happy-helpers
38
- requirement: &70302468085720 !ruby/object:Gem::Requirement
38
+ requirement: &70246363042320 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ~>
42
42
  - !ruby/object:Gem::Version
43
- version: 0.1.0.pre10
43
+ version: 0.1.0.pre11
44
44
  type: :runtime
45
45
  prerelease: false
46
- version_requirements: *70302468085720
46
+ version_requirements: *70246363042320
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: allowance
49
- requirement: &70302468084660 !ruby/object:Gem::Requirement
49
+ requirement: &70246363058000 !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: *70302468084660
57
+ version_requirements: *70246363058000
58
58
  - !ruby/object:Gem::Dependency
59
59
  name: happy-cli
60
- requirement: &70302468122420 !ruby/object:Gem::Requirement
60
+ requirement: &70246363056880 !ruby/object:Gem::Requirement
61
61
  none: false
62
62
  requirements:
63
63
  - - ! '>='
@@ -65,10 +65,10 @@ dependencies:
65
65
  version: 0.1.0.pre1
66
66
  type: :runtime
67
67
  prerelease: false
68
- version_requirements: *70302468122420
68
+ version_requirements: *70246363056880
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: rake
71
- requirement: &70302468120940 !ruby/object:Gem::Requirement
71
+ requirement: &70246363056380 !ruby/object:Gem::Requirement
72
72
  none: false
73
73
  requirements:
74
74
  - - ! '>='
@@ -76,10 +76,10 @@ dependencies:
76
76
  version: '0'
77
77
  type: :development
78
78
  prerelease: false
79
- version_requirements: *70302468120940
79
+ version_requirements: *70246363056380
80
80
  - !ruby/object:Gem::Dependency
81
81
  name: rspec
82
- requirement: &70302468119720 !ruby/object:Gem::Requirement
82
+ requirement: &70246363055680 !ruby/object:Gem::Requirement
83
83
  none: false
84
84
  requirements:
85
85
  - - ~>
@@ -87,10 +87,10 @@ dependencies:
87
87
  version: '2.8'
88
88
  type: :development
89
89
  prerelease: false
90
- version_requirements: *70302468119720
90
+ version_requirements: *70246363055680
91
91
  - !ruby/object:Gem::Dependency
92
92
  name: rspec-html-matchers
93
- requirement: &70302468119000 !ruby/object:Gem::Requirement
93
+ requirement: &70246363054880 !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: *70302468119000
101
+ version_requirements: *70246363054880
102
102
  - !ruby/object:Gem::Dependency
103
103
  name: rack-test
104
- requirement: &70302468118500 !ruby/object:Gem::Requirement
104
+ requirement: &70246363054000 !ruby/object:Gem::Requirement
105
105
  none: false
106
106
  requirements:
107
107
  - - ! '>='
@@ -109,10 +109,10 @@ dependencies:
109
109
  version: '0'
110
110
  type: :development
111
111
  prerelease: false
112
- version_requirements: *70302468118500
112
+ version_requirements: *70246363054000
113
113
  - !ruby/object:Gem::Dependency
114
114
  name: watchr
115
- requirement: &70302468118060 !ruby/object:Gem::Requirement
115
+ requirement: &70246363053540 !ruby/object:Gem::Requirement
116
116
  none: false
117
117
  requirements:
118
118
  - - ! '>='
@@ -120,7 +120,7 @@ dependencies:
120
120
  version: '0'
121
121
  type: :development
122
122
  prerelease: false
123
- version_requirements: *70302468118060
123
+ version_requirements: *70246363053540
124
124
  description: A happy little toolkit for writing web applications.
125
125
  email:
126
126
  - hendrik@mans.de
@@ -137,25 +137,30 @@ files:
137
137
  - LICENSE
138
138
  - README.md
139
139
  - Rakefile
140
+ - example/config.ru
141
+ - example/views/index.erb
142
+ - example/views/layout.erb
140
143
  - happy.gemspec
141
144
  - lib/happy.rb
142
- - lib/happy/context.rb
143
- - lib/happy/context/helpers.rb
144
145
  - lib/happy/controller.rb
145
146
  - lib/happy/controller/actions.rb
147
+ - lib/happy/controller/cascadable.rb
146
148
  - lib/happy/controller/configurable.rb
149
+ - lib/happy/controller/helpers.rb
150
+ - lib/happy/controller/permissions.rb
147
151
  - lib/happy/controller/rackable.rb
148
152
  - lib/happy/controller/routing.rb
149
153
  - lib/happy/errors.rb
150
154
  - lib/happy/extras/code_reloader.rb
151
- - lib/happy/extras/permissions.rb
152
155
  - lib/happy/extras/resources.rb
153
156
  - lib/happy/extras/scriptable.rb
154
157
  - lib/happy/extras/static.rb
155
158
  - lib/happy/files/error.erb
156
159
  - lib/happy/request.rb
160
+ - lib/happy/response.rb
157
161
  - lib/happy/version.rb
158
162
  - spec/controller/actions_spec.rb
163
+ - spec/controller/cascadable_spec.rb
159
164
  - spec/controller/routing_spec.rb
160
165
  - spec/controller_spec.rb
161
166
  - spec/happy_spec.rb
@@ -186,6 +191,7 @@ specification_version: 3
186
191
  summary: A happy little toolkit for writing web applications.
187
192
  test_files:
188
193
  - spec/controller/actions_spec.rb
194
+ - spec/controller/cascadable_spec.rb
189
195
  - spec/controller/routing_spec.rb
190
196
  - spec/controller_spec.rb
191
197
  - spec/happy_spec.rb
@@ -1,88 +0,0 @@
1
- require 'happy/request'
2
- require 'happy/context/helpers'
3
-
4
- module Happy
5
- # Represents the current request and its respective application state.
6
- # Not only does this class wrap around both the incoming {#request} and the
7
- # generated {#response}, but it is also used as the scope for all templates
8
- # rendered through {#render_template}.
9
- #
10
- # (In case you're wondering, a particular request's instance of #{Context} is
11
- # created from the Rack environment by #{Controller#context} when first accessed.)
12
- #
13
- # == View Helpers
14
- #
15
- # If you're coming from other web frameworks and looking for the right place
16
- # to add "view helpers", this is it, since all templates being rendered use
17
- # the request's instance of {Context} as their scope.
18
- #
19
- # The most convenient way of extending this class is through #{Happy.context}.
20
- #
21
- # Happy.context do
22
- # def some_helper
23
- # "I'm a view helper!"
24
- # end
25
- # end
26
- #
27
- # In addition to view helpers, the context is the place to add methods
28
- # dealing with the current request scope, eg. methods like 'current_user'.
29
- #
30
- class Context
31
- include Helpers
32
-
33
- # Instance of {Happy::Request} representing the current HTTP request.
34
- attr_reader :request
35
-
36
- # The Rack::Response instance being used to compose the response.
37
- attr_accessor :response
38
-
39
- # The current layout template to be used when rendering the response.
40
- attr_accessor :layout
41
-
42
- # Array containing path parts that are yet to be handled.
43
- attr_reader :remaining_path
44
-
45
- # Array of path parts that have been handled so far.
46
- attr_reader :previous_path
47
-
48
- delegate :params, :session, :to => :request
49
-
50
- # Initializes a new {Context} instance from a Rack environment hash.
51
- #
52
- # @param [Hash] env Rack environment hash
53
- #
54
- def initialize(env)
55
- @request = Happy::Request.new(env)
56
- @response = Rack::Response.new
57
-
58
- @remaining_path = @request.path.split('/').reject {|s| s.blank? }
59
- @previous_path = []
60
- @layout = nil
61
- @controller = nil
62
- end
63
-
64
- # @note
65
- # This method is mostly used internally by Happy. You will not need
66
- # to call it from your own controllers or applications.
67
- #
68
- # Execute the provided block, but register the provided {Controller}
69
- # instance as the controller currently handling the request. Call this
70
- # whenever you're passing control from one controller to another.
71
- #
72
- # @param [Controller] new_controller The {Controller} instance to set as the current controller
73
- # @return Results of provided block.
74
- #
75
- def with_controller(new_controller)
76
- # remember previous controller
77
- old_controller = @controller
78
- @controller = new_controller
79
-
80
- # execute block
81
- yield if block_given?
82
- ensure
83
- # switch back to previous controller
84
- @controller = old_controller
85
- end
86
-
87
- end
88
- end
@@ -1,32 +0,0 @@
1
- require 'allowance'
2
-
3
- module Happy
4
- module Extras
5
- module Permissions
6
- module ContextExtensions
7
- extend ActiveSupport::Concern
8
-
9
- def permissions(&blk)
10
- (@permissions ||= Allowance::Permissions.new).tap do |p|
11
- if blk
12
- blk.arity == 0 ? p.instance_exec(&blk) : blk.call(p)
13
- end
14
- end
15
- end
16
-
17
- alias_method :can, :permissions
18
- end
19
-
20
- module ControllerExtensions
21
- extend ActiveSupport::Concern
22
-
23
- included do
24
- delegate :permissions, :can, :to => :context
25
- end
26
- end
27
- end
28
- end
29
- end
30
-
31
- Happy::Context.send(:include, Happy::Extras::Permissions::ContextExtensions)
32
- Happy::Controller.send(:include, Happy::Extras::Permissions::ControllerExtensions)