happy 0.1.0.pre.1 → 0.1.0.pre.2
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/.rspec +1 -0
- data/.yardopt +1 -0
- data/Rakefile +5 -0
- data/happy.gemspec +5 -0
- data/lib/happy.rb +4 -3
- data/lib/happy/context.rb +2 -2
- data/lib/happy/context_ext/helpers.rb +39 -0
- data/lib/happy/controller.rb +6 -6
- data/lib/happy/controller_ext/actions.rb +80 -0
- data/lib/happy/controller_ext/rackable.rb +26 -0
- data/lib/happy/controller_ext/routing.rb +58 -0
- data/lib/happy/ext/permissions.rb +38 -0
- data/lib/happy/ext/resources.rb +116 -0
- data/lib/happy/ext/static.rb +9 -0
- data/lib/happy/version.rb +1 -1
- data/spec/controller_spec.rb +7 -0
- data/spec/spec_helper.rb +9 -0
- metadata +67 -17
- data/lib/happy/actions.rb +0 -78
- data/lib/happy/helpers.rb +0 -37
- data/lib/happy/permissions.rb +0 -34
- data/lib/happy/rackable.rb +0 -24
- data/lib/happy/resources.rb +0 -112
- data/lib/happy/routing.rb +0 -56
- data/lib/happy/static.rb +0 -7
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/.yardopt
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--no-private --protected --embed-mixins lib/**/*.rb - README LEGAL
|
data/Rakefile
CHANGED
data/happy.gemspec
CHANGED
@@ -19,4 +19,9 @@ Gem::Specification.new do |gem|
|
|
19
19
|
gem.add_dependency 'rack', '~> 1.4'
|
20
20
|
gem.add_dependency 'happy-helpers' # TODO: , '~> 0.1.0'
|
21
21
|
gem.add_dependency 'allowance', '>= 0.1.1'
|
22
|
+
|
23
|
+
gem.add_development_dependency 'rake'
|
24
|
+
gem.add_development_dependency 'rspec', '~> 2.8'
|
25
|
+
gem.add_development_dependency 'rspec-html-matchers'
|
26
|
+
gem.add_development_dependency 'rack-test'
|
22
27
|
end
|
data/lib/happy.rb
CHANGED
@@ -2,11 +2,12 @@ require 'active_support/all' # SMELL
|
|
2
2
|
|
3
3
|
require 'happy/context'
|
4
4
|
require 'happy/controller'
|
5
|
-
require 'happy/static'
|
6
5
|
|
7
6
|
module Happy
|
8
|
-
|
9
|
-
|
7
|
+
module Errors
|
8
|
+
class Base < StandardError ; end
|
9
|
+
class NotFound < Base ; end
|
10
|
+
end
|
10
11
|
|
11
12
|
def self.env
|
12
13
|
ActiveSupport::StringInquirer.new(ENV['RACK_ENV'] || 'development')
|
data/lib/happy/context.rb
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
require 'happy/request'
|
2
|
-
require 'happy/helpers'
|
2
|
+
require 'happy/context_ext/helpers'
|
3
3
|
|
4
4
|
module Happy
|
5
5
|
class Context
|
6
|
-
include Helpers
|
6
|
+
include ContextExtensions::Helpers
|
7
7
|
|
8
8
|
attr_reader :request, :response, :remaining_path
|
9
9
|
attr_accessor :layout, :controller
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'happy-helpers'
|
2
|
+
|
3
|
+
module Happy
|
4
|
+
module ContextExtensions
|
5
|
+
module Helpers
|
6
|
+
include HappyHelpers::Helpers
|
7
|
+
|
8
|
+
def render(what, options = {}, &blk)
|
9
|
+
case what
|
10
|
+
when String then render_template(what, options, &blk)
|
11
|
+
when Enumerable then what.map { |i| render(i, options, &blk) }.join
|
12
|
+
else render_resource(what, options)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def render_template(name, variables = {}, &blk)
|
17
|
+
HappyHelpers::Templates.render(name, self, variables, &blk)
|
18
|
+
end
|
19
|
+
|
20
|
+
def render_resource(resource, options = {})
|
21
|
+
# build name strings
|
22
|
+
singular_name = resource.class.to_s.tableize.singularize
|
23
|
+
plural_name = singular_name.pluralize
|
24
|
+
|
25
|
+
# set options
|
26
|
+
options = {
|
27
|
+
singular_name => resource
|
28
|
+
}.merge(options)
|
29
|
+
|
30
|
+
# render
|
31
|
+
render_template("#{plural_name}/_#{singular_name}.html.haml", options)
|
32
|
+
end
|
33
|
+
|
34
|
+
alias_method :h, :escape_html
|
35
|
+
alias_method :l, :localize
|
36
|
+
alias_method :t, :translate
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
data/lib/happy/controller.rb
CHANGED
@@ -1,12 +1,12 @@
|
|
1
|
-
require 'happy/routing'
|
2
|
-
require 'happy/actions'
|
3
|
-
require 'happy/rackable'
|
1
|
+
require 'happy/controller_ext/routing'
|
2
|
+
require 'happy/controller_ext/actions'
|
3
|
+
require 'happy/controller_ext/rackable'
|
4
4
|
|
5
5
|
module Happy
|
6
6
|
class Controller
|
7
|
-
include Routing
|
8
|
-
include Actions
|
9
|
-
include Rackable
|
7
|
+
include ControllerExtensions::Routing
|
8
|
+
include ControllerExtensions::Actions
|
9
|
+
include ControllerExtensions::Rackable
|
10
10
|
|
11
11
|
attr_reader :options, :env
|
12
12
|
|
@@ -0,0 +1,80 @@
|
|
1
|
+
module Happy
|
2
|
+
module ControllerExtensions
|
3
|
+
module Actions
|
4
|
+
def serve!(data, options = {})
|
5
|
+
# Don't serve if there are still bits of path remaining.
|
6
|
+
return unless remaining_path.empty?
|
7
|
+
|
8
|
+
# Don't serve is data is not a string.
|
9
|
+
return unless data.is_a?(String)
|
10
|
+
|
11
|
+
# Mix in default options
|
12
|
+
options = {
|
13
|
+
layout: context.layout
|
14
|
+
}.merge(options)
|
15
|
+
|
16
|
+
# Add optional headers et al
|
17
|
+
response.status = options[:status] if options.has_key?(:status)
|
18
|
+
response['Content-type'] = options[:content_type] if options.has_key?(:content_type)
|
19
|
+
|
20
|
+
# Apply layout, if available
|
21
|
+
if options[:layout]
|
22
|
+
data = render(options[:layout]) { data }
|
23
|
+
end
|
24
|
+
|
25
|
+
# Set response body and finish request
|
26
|
+
response.body = [data]
|
27
|
+
halt!
|
28
|
+
end
|
29
|
+
|
30
|
+
def halt!(message = :done)
|
31
|
+
throw message
|
32
|
+
end
|
33
|
+
|
34
|
+
def redirect!(to, status = 302)
|
35
|
+
header "Location", url_for(to)
|
36
|
+
response.status = status
|
37
|
+
halt!
|
38
|
+
end
|
39
|
+
|
40
|
+
def layout(name)
|
41
|
+
context.layout = name
|
42
|
+
end
|
43
|
+
|
44
|
+
def content_type(type)
|
45
|
+
header 'Content-type', type
|
46
|
+
end
|
47
|
+
|
48
|
+
def max_age(t, options = {})
|
49
|
+
options = {
|
50
|
+
:public => true,
|
51
|
+
:must_revalidate => true
|
52
|
+
}.merge(options)
|
53
|
+
|
54
|
+
s = []
|
55
|
+
s << 'public' if options[:public]
|
56
|
+
s << 'must-revalidate' if options[:must_revalidate]
|
57
|
+
s << "max-age=#{t.to_i}"
|
58
|
+
|
59
|
+
cache_control s.join(', ')
|
60
|
+
end
|
61
|
+
|
62
|
+
def cache_control(s)
|
63
|
+
header 'Cache-control', s
|
64
|
+
end
|
65
|
+
|
66
|
+
def header(name, value)
|
67
|
+
response[name] = value
|
68
|
+
end
|
69
|
+
|
70
|
+
def invoke(klass, options = {}, &blk)
|
71
|
+
klass.new(env, options, &blk).perform
|
72
|
+
end
|
73
|
+
|
74
|
+
def run(app)
|
75
|
+
context.response = app.call(request.env)
|
76
|
+
halt!
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Happy
|
2
|
+
module ControllerExtensions
|
3
|
+
module Rackable
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
def call(env)
|
7
|
+
@env = env
|
8
|
+
|
9
|
+
catch :done do
|
10
|
+
serve! perform
|
11
|
+
|
12
|
+
# If we get here, #serve decided not to serve.
|
13
|
+
raise Errors::NotFound
|
14
|
+
end
|
15
|
+
|
16
|
+
response
|
17
|
+
end
|
18
|
+
|
19
|
+
module ClassMethods
|
20
|
+
def call(env)
|
21
|
+
new.call(env)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module Happy
|
2
|
+
module ControllerExtensions
|
3
|
+
module Routing
|
4
|
+
def path_to_regexp(path)
|
5
|
+
path = ":#{path}" if path.is_a?(Symbol)
|
6
|
+
Regexp.compile('^'+path.gsub(/\)/, ')?').gsub(/\//, '\/').gsub(/\./, '\.').gsub(/:(\w+)/, '(?<\\1>.+)')+'$')
|
7
|
+
end
|
8
|
+
|
9
|
+
def path(*args, &blk)
|
10
|
+
options = (args.pop if args.last.is_a?(Hash)) || {}
|
11
|
+
args = [nil] if args.empty?
|
12
|
+
|
13
|
+
args.each do |name|
|
14
|
+
if name.present?
|
15
|
+
path_match = path_to_regexp(name).match(remaining_path.first)
|
16
|
+
end
|
17
|
+
|
18
|
+
method_matched = [nil, request.request_method.downcase.to_sym].include?(options[:method])
|
19
|
+
path_matched = (path_match || (name.nil? && remaining_path.empty?))
|
20
|
+
|
21
|
+
# Only do something here if method and requested path both match
|
22
|
+
if path_matched && method_matched
|
23
|
+
# Transfer variables contained in path name to params hash
|
24
|
+
if path_match
|
25
|
+
path_match.names.each { |k| request.params[k] = path_match[k] }
|
26
|
+
remaining_path.shift
|
27
|
+
end
|
28
|
+
|
29
|
+
serve! instance_exec(&blk)
|
30
|
+
|
31
|
+
# If we get here, #serve decided not to serve.
|
32
|
+
raise Errors::NotFound
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def get(*args, &blk)
|
38
|
+
args.last.is_a?(Hash) ? args.last.merge(method: :get) : args.push(method: :get)
|
39
|
+
path(*args, &blk)
|
40
|
+
end
|
41
|
+
|
42
|
+
def post(*args, &blk)
|
43
|
+
args.last.is_a?(Hash) ? args.last.merge(method: :post) : args.push(method: :post)
|
44
|
+
path(*args, &blk)
|
45
|
+
end
|
46
|
+
|
47
|
+
def put(*args, &blk)
|
48
|
+
args.last.is_a?(Hash) ? args.last.merge(method: :put) : args.push(method: :put)
|
49
|
+
path(*args, &blk)
|
50
|
+
end
|
51
|
+
|
52
|
+
def delete(*args, &blk)
|
53
|
+
args.last.is_a?(Hash) ? args.last.merge(method: :delete) : args.push(method: :delete)
|
54
|
+
path(*args, &blk)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'allowance'
|
2
|
+
|
3
|
+
module Happy
|
4
|
+
module Extensions
|
5
|
+
module Permissions
|
6
|
+
module ContextExtensions
|
7
|
+
extend ActiveSupport::Concern
|
8
|
+
|
9
|
+
def permissions(&blk)
|
10
|
+
@permissions ||= Allowance.define
|
11
|
+
end
|
12
|
+
|
13
|
+
def can?(*args)
|
14
|
+
permissions.allowed?(*args)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
module ControllerExtensions
|
19
|
+
extend ActiveSupport::Concern
|
20
|
+
|
21
|
+
included do
|
22
|
+
delegate :can?, :to => :context
|
23
|
+
end
|
24
|
+
|
25
|
+
module ClassMethods
|
26
|
+
attr_accessor :permissions_blk
|
27
|
+
|
28
|
+
def permissions(&blk)
|
29
|
+
self.permissions_blk = blk
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
Happy::Context.send(:include, Happy::Extensions::Permissions::ContextExtensions)
|
38
|
+
Happy::Controller.send(:include, Happy::Extensions::Permissions::ControllerExtensions)
|
@@ -0,0 +1,116 @@
|
|
1
|
+
require 'happy/ext/permissions'
|
2
|
+
|
3
|
+
module Happy
|
4
|
+
module Extensions
|
5
|
+
module Resources
|
6
|
+
module ControllerExtensions
|
7
|
+
def resource(klass, options = {}, &blk)
|
8
|
+
invoke ResourceMounter, options.merge(:class => klass), &blk
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
class ResourceMounter < Happy::Controller
|
13
|
+
def render_resource_template(name)
|
14
|
+
render "#{options[:plural_name]}/#{name}.html.haml"
|
15
|
+
end
|
16
|
+
|
17
|
+
def resource
|
18
|
+
options[:class]
|
19
|
+
end
|
20
|
+
|
21
|
+
def resource_with_permission_scope(*args)
|
22
|
+
context.permissions.scoped_model(*args, options[:class])
|
23
|
+
end
|
24
|
+
|
25
|
+
def require_permission!(*args)
|
26
|
+
raise "not allowed" unless can?(*args, options[:class])
|
27
|
+
end
|
28
|
+
|
29
|
+
def set_plural_variable(v)
|
30
|
+
context.instance_variable_set "@#{options[:plural_name]}", v
|
31
|
+
end
|
32
|
+
|
33
|
+
def plural_variable
|
34
|
+
context.instance_variable_get "@#{options[:plural_name]}"
|
35
|
+
end
|
36
|
+
|
37
|
+
def set_singular_variable(v)
|
38
|
+
context.instance_variable_set "@#{options[:singular_name]}", v
|
39
|
+
end
|
40
|
+
|
41
|
+
def singular_variable
|
42
|
+
context.instance_variable_get "@#{options[:singular_name]}"
|
43
|
+
end
|
44
|
+
|
45
|
+
def do_index
|
46
|
+
require_permission! :index
|
47
|
+
set_plural_variable resource_with_permission_scope(:index).all
|
48
|
+
render_resource_template 'index'
|
49
|
+
end
|
50
|
+
|
51
|
+
def do_show
|
52
|
+
require_permission! :show
|
53
|
+
set_singular_variable resource_with_permission_scope(:show).find(params['id'])
|
54
|
+
render_resource_template 'show'
|
55
|
+
end
|
56
|
+
|
57
|
+
def do_new
|
58
|
+
require_permission! :new
|
59
|
+
set_singular_variable resource_with_permission_scope(:new).new(params[options[:singular_name]], :as => options[:role])
|
60
|
+
render_resource_template 'new'
|
61
|
+
end
|
62
|
+
|
63
|
+
def do_create
|
64
|
+
require_permission! :create
|
65
|
+
set_singular_variable resource_with_permission_scope(:create).new(params[options[:singular_name]], :as => options[:role])
|
66
|
+
|
67
|
+
if singular_variable.save
|
68
|
+
redirect! singular_variable
|
69
|
+
else
|
70
|
+
render_resource_template 'new'
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def do_edit
|
75
|
+
require_permission! :edit
|
76
|
+
set_singular_variable resource_with_permission_scope(:edit).find(params['id'])
|
77
|
+
render_resource_template 'edit'
|
78
|
+
end
|
79
|
+
|
80
|
+
def do_update
|
81
|
+
require_permission! :update
|
82
|
+
set_singular_variable resource_with_permission_scope(:update).find(params['id'])
|
83
|
+
singular_variable.assign_attributes params[options[:singular_name]], :as => options[:role]
|
84
|
+
|
85
|
+
if singular_variable.save
|
86
|
+
redirect! singular_variable
|
87
|
+
else
|
88
|
+
render_resource_template 'edit'
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def route
|
93
|
+
@options = {
|
94
|
+
singular_name: options[:class].to_s.tableize.singularize,
|
95
|
+
plural_name: options[:class].to_s.tableize.pluralize
|
96
|
+
}.merge(@options)
|
97
|
+
|
98
|
+
path options[:plural_name] do
|
99
|
+
get('new') { do_new }
|
100
|
+
|
101
|
+
path :id do
|
102
|
+
get { do_show }
|
103
|
+
post { do_update }
|
104
|
+
get('edit') { do_edit }
|
105
|
+
end
|
106
|
+
|
107
|
+
post { do_create }
|
108
|
+
get { do_index }
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
Happy::Controller.send(:include, Happy::Extensions::Resources::ControllerExtensions)
|
data/lib/happy/version.rb
CHANGED
data/spec/spec_helper.rb
ADDED
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.2
|
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: &70265405180720 !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: *70265405180720
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: rack
|
27
|
-
requirement: &
|
27
|
+
requirement: &70265405180020 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ~>
|
@@ -32,10 +32,10 @@ dependencies:
|
|
32
32
|
version: '1.4'
|
33
33
|
type: :runtime
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *70265405180020
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: happy-helpers
|
38
|
-
requirement: &
|
38
|
+
requirement: &70265405178080 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ! '>='
|
@@ -43,10 +43,10 @@ dependencies:
|
|
43
43
|
version: '0'
|
44
44
|
type: :runtime
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *70265405178080
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: allowance
|
49
|
-
requirement: &
|
49
|
+
requirement: &70265405175720 !ruby/object:Gem::Requirement
|
50
50
|
none: false
|
51
51
|
requirements:
|
52
52
|
- - ! '>='
|
@@ -54,7 +54,51 @@ dependencies:
|
|
54
54
|
version: 0.1.1
|
55
55
|
type: :runtime
|
56
56
|
prerelease: false
|
57
|
-
version_requirements: *
|
57
|
+
version_requirements: *70265405175720
|
58
|
+
- !ruby/object:Gem::Dependency
|
59
|
+
name: rake
|
60
|
+
requirement: &70265405174800 !ruby/object:Gem::Requirement
|
61
|
+
none: false
|
62
|
+
requirements:
|
63
|
+
- - ! '>='
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: '0'
|
66
|
+
type: :development
|
67
|
+
prerelease: false
|
68
|
+
version_requirements: *70265405174800
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rspec
|
71
|
+
requirement: &70265405173920 !ruby/object:Gem::Requirement
|
72
|
+
none: false
|
73
|
+
requirements:
|
74
|
+
- - ~>
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '2.8'
|
77
|
+
type: :development
|
78
|
+
prerelease: false
|
79
|
+
version_requirements: *70265405173920
|
80
|
+
- !ruby/object:Gem::Dependency
|
81
|
+
name: rspec-html-matchers
|
82
|
+
requirement: &70265405172780 !ruby/object:Gem::Requirement
|
83
|
+
none: false
|
84
|
+
requirements:
|
85
|
+
- - ! '>='
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
version: '0'
|
88
|
+
type: :development
|
89
|
+
prerelease: false
|
90
|
+
version_requirements: *70265405172780
|
91
|
+
- !ruby/object:Gem::Dependency
|
92
|
+
name: rack-test
|
93
|
+
requirement: &70265405170780 !ruby/object:Gem::Requirement
|
94
|
+
none: false
|
95
|
+
requirements:
|
96
|
+
- - ! '>='
|
97
|
+
- !ruby/object:Gem::Version
|
98
|
+
version: '0'
|
99
|
+
type: :development
|
100
|
+
prerelease: false
|
101
|
+
version_requirements: *70265405170780
|
58
102
|
description: A happy little toolkit for writing web applications.
|
59
103
|
email:
|
60
104
|
- hendrik@mans.de
|
@@ -63,23 +107,27 @@ extensions: []
|
|
63
107
|
extra_rdoc_files: []
|
64
108
|
files:
|
65
109
|
- .gitignore
|
110
|
+
- .rspec
|
111
|
+
- .yardopt
|
66
112
|
- Gemfile
|
67
113
|
- LICENSE
|
68
114
|
- README.md
|
69
115
|
- Rakefile
|
70
116
|
- happy.gemspec
|
71
117
|
- lib/happy.rb
|
72
|
-
- lib/happy/actions.rb
|
73
118
|
- lib/happy/context.rb
|
119
|
+
- lib/happy/context_ext/helpers.rb
|
74
120
|
- lib/happy/controller.rb
|
75
|
-
- lib/happy/
|
76
|
-
- lib/happy/
|
77
|
-
- lib/happy/
|
121
|
+
- lib/happy/controller_ext/actions.rb
|
122
|
+
- lib/happy/controller_ext/rackable.rb
|
123
|
+
- lib/happy/controller_ext/routing.rb
|
124
|
+
- lib/happy/ext/permissions.rb
|
125
|
+
- lib/happy/ext/resources.rb
|
126
|
+
- lib/happy/ext/static.rb
|
78
127
|
- lib/happy/request.rb
|
79
|
-
- lib/happy/resources.rb
|
80
|
-
- lib/happy/routing.rb
|
81
|
-
- lib/happy/static.rb
|
82
128
|
- lib/happy/version.rb
|
129
|
+
- spec/controller_spec.rb
|
130
|
+
- spec/spec_helper.rb
|
83
131
|
homepage: https://github.com/hmans/happy
|
84
132
|
licenses: []
|
85
133
|
post_install_message:
|
@@ -104,5 +152,7 @@ rubygems_version: 1.8.11
|
|
104
152
|
signing_key:
|
105
153
|
specification_version: 3
|
106
154
|
summary: A happy little toolkit for writing web applications.
|
107
|
-
test_files:
|
155
|
+
test_files:
|
156
|
+
- spec/controller_spec.rb
|
157
|
+
- spec/spec_helper.rb
|
108
158
|
has_rdoc:
|
data/lib/happy/actions.rb
DELETED
@@ -1,78 +0,0 @@
|
|
1
|
-
module Happy
|
2
|
-
module Actions
|
3
|
-
def serve!(data, options = {})
|
4
|
-
# Don't serve if there are still bits of path remaining.
|
5
|
-
return unless remaining_path.empty?
|
6
|
-
|
7
|
-
# Don't serve is data is not a string.
|
8
|
-
return unless data.is_a?(String)
|
9
|
-
|
10
|
-
# Mix in default options
|
11
|
-
options = {
|
12
|
-
layout: context.layout
|
13
|
-
}.merge(options)
|
14
|
-
|
15
|
-
# Add optional headers et al
|
16
|
-
response.status = options[:status] if options.has_key?(:status)
|
17
|
-
response['Content-type'] = options[:content_type] if options.has_key?(:content_type)
|
18
|
-
|
19
|
-
# Apply layout, if available
|
20
|
-
if options[:layout]
|
21
|
-
data = render(options[:layout]) { data }
|
22
|
-
end
|
23
|
-
|
24
|
-
# Set response body and finish request
|
25
|
-
response.body = [data]
|
26
|
-
halt!
|
27
|
-
end
|
28
|
-
|
29
|
-
def halt!(message = :done)
|
30
|
-
throw message
|
31
|
-
end
|
32
|
-
|
33
|
-
def redirect!(to, status = 302)
|
34
|
-
header "Location", url_for(to)
|
35
|
-
response.status = status
|
36
|
-
halt!
|
37
|
-
end
|
38
|
-
|
39
|
-
def layout(name)
|
40
|
-
context.layout = name
|
41
|
-
end
|
42
|
-
|
43
|
-
def content_type(type)
|
44
|
-
header 'Content-type', type
|
45
|
-
end
|
46
|
-
|
47
|
-
def max_age(t, options = {})
|
48
|
-
options = {
|
49
|
-
:public => true,
|
50
|
-
:must_revalidate => true
|
51
|
-
}.merge(options)
|
52
|
-
|
53
|
-
s = []
|
54
|
-
s << 'public' if options[:public]
|
55
|
-
s << 'must-revalidate' if options[:must_revalidate]
|
56
|
-
s << "max-age=#{t.to_i}"
|
57
|
-
|
58
|
-
cache_control s.join(', ')
|
59
|
-
end
|
60
|
-
|
61
|
-
def cache_control(s)
|
62
|
-
header 'Cache-control', s
|
63
|
-
end
|
64
|
-
|
65
|
-
def header(name, value)
|
66
|
-
response[name] = value
|
67
|
-
end
|
68
|
-
|
69
|
-
def invoke(klass, options = {}, &blk)
|
70
|
-
klass.new(env, options, &blk).perform
|
71
|
-
end
|
72
|
-
|
73
|
-
def run(app)
|
74
|
-
context.response = app.call(request.env)
|
75
|
-
halt!
|
76
|
-
end
|
77
|
-
end
|
78
|
-
end
|
data/lib/happy/helpers.rb
DELETED
@@ -1,37 +0,0 @@
|
|
1
|
-
require 'happy-helpers'
|
2
|
-
|
3
|
-
module Happy
|
4
|
-
module Helpers
|
5
|
-
include HappyHelpers::Helpers
|
6
|
-
|
7
|
-
def render(what, options = {}, &blk)
|
8
|
-
case what
|
9
|
-
when String then render_template(what, options, &blk)
|
10
|
-
when Enumerable then what.map { |i| render(i, options, &blk) }.join
|
11
|
-
else render_resource(what, options)
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
def render_template(name, variables = {}, &blk)
|
16
|
-
HappyHelpers::Templates.render(name, self, variables, &blk)
|
17
|
-
end
|
18
|
-
|
19
|
-
def render_resource(resource, options = {})
|
20
|
-
# build name strings
|
21
|
-
singular_name = resource.class.to_s.tableize.singularize
|
22
|
-
plural_name = singular_name.pluralize
|
23
|
-
|
24
|
-
# set options
|
25
|
-
options = {
|
26
|
-
singular_name => resource
|
27
|
-
}.merge(options)
|
28
|
-
|
29
|
-
# render
|
30
|
-
render_template("#{plural_name}/_#{singular_name}.html.haml", options)
|
31
|
-
end
|
32
|
-
|
33
|
-
alias_method :h, :escape_html
|
34
|
-
alias_method :l, :localize
|
35
|
-
alias_method :t, :translate
|
36
|
-
end
|
37
|
-
end
|
data/lib/happy/permissions.rb
DELETED
@@ -1,34 +0,0 @@
|
|
1
|
-
module Happy
|
2
|
-
module Permissions
|
3
|
-
module ContextExtensions
|
4
|
-
extend ActiveSupport::Concern
|
5
|
-
|
6
|
-
def permissions(&blk)
|
7
|
-
@permissions ||= Allowance.define
|
8
|
-
end
|
9
|
-
|
10
|
-
def can?(*args)
|
11
|
-
permissions.allowed?(*args)
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
module ControllerExtensions
|
16
|
-
extend ActiveSupport::Concern
|
17
|
-
|
18
|
-
included do
|
19
|
-
delegate :can?, :to => :context
|
20
|
-
end
|
21
|
-
|
22
|
-
module ClassMethods
|
23
|
-
attr_accessor :permissions_blk
|
24
|
-
|
25
|
-
def permissions(&blk)
|
26
|
-
self.permissions_blk = blk
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
Happy::Context.send(:include, Happy::Permissions::ContextExtensions)
|
34
|
-
Happy::Controller.send(:include, Happy::Permissions::ControllerExtensions)
|
data/lib/happy/rackable.rb
DELETED
@@ -1,24 +0,0 @@
|
|
1
|
-
module Happy
|
2
|
-
module Rackable
|
3
|
-
extend ActiveSupport::Concern
|
4
|
-
|
5
|
-
def call(env)
|
6
|
-
@env = env
|
7
|
-
|
8
|
-
catch :done do
|
9
|
-
serve! perform
|
10
|
-
|
11
|
-
# If we get here, #serve decided not to serve.
|
12
|
-
raise NotFoundError
|
13
|
-
end
|
14
|
-
|
15
|
-
response
|
16
|
-
end
|
17
|
-
|
18
|
-
module ClassMethods
|
19
|
-
def call(env)
|
20
|
-
new.call(env)
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
data/lib/happy/resources.rb
DELETED
@@ -1,112 +0,0 @@
|
|
1
|
-
module Happy
|
2
|
-
module Resources
|
3
|
-
module ControllerExtensions
|
4
|
-
def resource(klass, options = {}, &blk)
|
5
|
-
invoke Happy::Resources::ResourceMounter, options.merge(:class => klass), &blk
|
6
|
-
end
|
7
|
-
end
|
8
|
-
|
9
|
-
class ResourceMounter < Happy::Controller
|
10
|
-
def render_resource_template(name)
|
11
|
-
render "#{options[:plural_name]}/#{name}.html.haml"
|
12
|
-
end
|
13
|
-
|
14
|
-
def resource
|
15
|
-
options[:class]
|
16
|
-
end
|
17
|
-
|
18
|
-
def resource_with_permission_scope(*args)
|
19
|
-
context.permissions.scoped_model(*args, options[:class])
|
20
|
-
end
|
21
|
-
|
22
|
-
def require_permission!(*args)
|
23
|
-
raise "not allowed" unless can?(*args, options[:class])
|
24
|
-
end
|
25
|
-
|
26
|
-
def set_plural_variable(v)
|
27
|
-
context.instance_variable_set "@#{options[:plural_name]}", v
|
28
|
-
end
|
29
|
-
|
30
|
-
def plural_variable
|
31
|
-
context.instance_variable_get "@#{options[:plural_name]}"
|
32
|
-
end
|
33
|
-
|
34
|
-
def set_singular_variable(v)
|
35
|
-
context.instance_variable_set "@#{options[:singular_name]}", v
|
36
|
-
end
|
37
|
-
|
38
|
-
def singular_variable
|
39
|
-
context.instance_variable_get "@#{options[:singular_name]}"
|
40
|
-
end
|
41
|
-
|
42
|
-
def do_index
|
43
|
-
require_permission! :index
|
44
|
-
set_plural_variable resource_with_permission_scope(:index).all
|
45
|
-
render_resource_template 'index'
|
46
|
-
end
|
47
|
-
|
48
|
-
def do_show
|
49
|
-
require_permission! :show
|
50
|
-
set_singular_variable resource_with_permission_scope(:show).find(params['id'])
|
51
|
-
render_resource_template 'show'
|
52
|
-
end
|
53
|
-
|
54
|
-
def do_new
|
55
|
-
require_permission! :new
|
56
|
-
set_singular_variable resource_with_permission_scope(:new).new(params[options[:singular_name]], :as => options[:role])
|
57
|
-
render_resource_template 'new'
|
58
|
-
end
|
59
|
-
|
60
|
-
def do_create
|
61
|
-
require_permission! :create
|
62
|
-
set_singular_variable resource_with_permission_scope(:create).new(params[options[:singular_name]], :as => options[:role])
|
63
|
-
|
64
|
-
if singular_variable.save
|
65
|
-
redirect! singular_variable
|
66
|
-
else
|
67
|
-
render_resource_template 'new'
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
def do_edit
|
72
|
-
require_permission! :edit
|
73
|
-
set_singular_variable resource_with_permission_scope(:edit).find(params['id'])
|
74
|
-
render_resource_template 'edit'
|
75
|
-
end
|
76
|
-
|
77
|
-
def do_update
|
78
|
-
require_permission! :update
|
79
|
-
set_singular_variable resource_with_permission_scope(:update).find(params['id'])
|
80
|
-
singular_variable.assign_attributes params[options[:singular_name]], :as => options[:role]
|
81
|
-
|
82
|
-
if singular_variable.save
|
83
|
-
redirect! singular_variable
|
84
|
-
else
|
85
|
-
render_resource_template 'edit'
|
86
|
-
end
|
87
|
-
end
|
88
|
-
|
89
|
-
def route
|
90
|
-
@options = {
|
91
|
-
singular_name: options[:class].to_s.tableize.singularize,
|
92
|
-
plural_name: options[:class].to_s.tableize.pluralize
|
93
|
-
}.merge(@options)
|
94
|
-
|
95
|
-
path options[:plural_name] do
|
96
|
-
get('new') { do_new }
|
97
|
-
|
98
|
-
path :id do
|
99
|
-
get { do_show }
|
100
|
-
post { do_update }
|
101
|
-
get('edit') { do_edit }
|
102
|
-
end
|
103
|
-
|
104
|
-
post { do_create }
|
105
|
-
get { do_index }
|
106
|
-
end
|
107
|
-
end
|
108
|
-
end
|
109
|
-
end
|
110
|
-
end
|
111
|
-
|
112
|
-
Happy::Controller.send(:include, Happy::Resources::ControllerExtensions)
|
data/lib/happy/routing.rb
DELETED
@@ -1,56 +0,0 @@
|
|
1
|
-
module Happy
|
2
|
-
module Routing
|
3
|
-
def path_to_regexp(path)
|
4
|
-
path = ":#{path}" if path.is_a?(Symbol)
|
5
|
-
Regexp.compile('^'+path.gsub(/\)/, ')?').gsub(/\//, '\/').gsub(/\./, '\.').gsub(/:(\w+)/, '(?<\\1>.+)')+'$')
|
6
|
-
end
|
7
|
-
|
8
|
-
def path(*args, &blk)
|
9
|
-
options = (args.pop if args.last.is_a?(Hash)) || {}
|
10
|
-
args = [nil] if args.empty?
|
11
|
-
|
12
|
-
args.each do |name|
|
13
|
-
if name.present?
|
14
|
-
path_match = path_to_regexp(name).match(remaining_path.first)
|
15
|
-
end
|
16
|
-
|
17
|
-
method_matched = [nil, request.request_method.downcase.to_sym].include?(options[:method])
|
18
|
-
path_matched = (path_match || (name.nil? && remaining_path.empty?))
|
19
|
-
|
20
|
-
# Only do something here if method and requested path both match
|
21
|
-
if path_matched && method_matched
|
22
|
-
# Transfer variables contained in path name to params hash
|
23
|
-
if path_match
|
24
|
-
path_match.names.each { |k| request.params[k] = path_match[k] }
|
25
|
-
remaining_path.shift
|
26
|
-
end
|
27
|
-
|
28
|
-
serve! instance_exec(&blk)
|
29
|
-
|
30
|
-
# If we get here, #serve decided not to serve.
|
31
|
-
raise NotFoundError
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
def get(*args, &blk)
|
37
|
-
args.last.is_a?(Hash) ? args.last.merge(method: :get) : args.push(method: :get)
|
38
|
-
path(*args, &blk)
|
39
|
-
end
|
40
|
-
|
41
|
-
def post(*args, &blk)
|
42
|
-
args.last.is_a?(Hash) ? args.last.merge(method: :post) : args.push(method: :post)
|
43
|
-
path(*args, &blk)
|
44
|
-
end
|
45
|
-
|
46
|
-
def put(*args, &blk)
|
47
|
-
args.last.is_a?(Hash) ? args.last.merge(method: :put) : args.push(method: :put)
|
48
|
-
path(*args, &blk)
|
49
|
-
end
|
50
|
-
|
51
|
-
def delete(*args, &blk)
|
52
|
-
args.last.is_a?(Hash) ? args.last.merge(method: :delete) : args.push(method: :delete)
|
53
|
-
path(*args, &blk)
|
54
|
-
end
|
55
|
-
end
|
56
|
-
end
|