racket-mvc 0.2.0 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d06a12ceb8db8f9e2cafd0d649048e03da1e7644
4
- data.tar.gz: 7534148f29e1c2c00b65800c4b1fa41ea3705a08
3
+ metadata.gz: 29d1cf6f2b573f99dc79d38f46c61bbc877b81c6
4
+ data.tar.gz: 114fceb1c2ff59e31a94b1300c1efbad34fc78cc
5
5
  SHA512:
6
- metadata.gz: a929335cdea51bbabbc0f0531de67cacf63177ec042f33dfd373454c2284e06603da7ee50b188584d76db7de02572bb99de0cbfdeb57259e903b2feb4d4470c0
7
- data.tar.gz: bb0f3f128237c989d4937d612d5c0b6dc9d248f72e7233fc5900672526d9c72760816ba2fa53ed50c784bcb1dbf2e602b00237e9bca07a7a06d0e89afe2cbb18
6
+ metadata.gz: fb0558de22c5ed965ea8955caa8aac5309cadaa4ed80f01d08cce38666575f3715bd3a84dd1d6e005d94aa191cc433cd5a123cf73169cfba005b9497094f7aff
7
+ data.tar.gz: b1b51dc4dcf51d057d472f1897b0e9cd92be66dad8abe06fe9eb7127bedc8e0122d3a58787acc2aee77027831abb0bbcab82bbff1bb85e64191675908062da0e
data/README.md CHANGED
@@ -26,9 +26,9 @@ whenever I am finished porting most of my old apps from Ramaze.
26
26
  Have a look in the `spec` directory. The code base have tests covering 100 per cent of the code and I am planning on keeping it that way. At the moment the code is tested on the following platforms (using [Travis CI](https://travis-ci.org/)):
27
27
 
28
28
  - ruby 1.9.3
29
- - ruby 2.0
30
- - ruby 2.1.6
31
- - ruby 2.2.2
29
+ - ruby 2.0.0
30
+ - ruby 2.1.7
31
+ - ruby 2.2.3
32
32
  - jruby 1.7 (1.9 mode only)
33
33
  - jruby 9.0.0.0
34
34
  - rbx-2 (latest version)
data/Rakefile CHANGED
@@ -1,20 +1,30 @@
1
1
  require 'rubygems'
2
2
  require 'bundler/setup'
3
3
 
4
- task default: %w[test]
4
+ desc "Run bacon tests"
5
+ task default: [:test]
5
6
 
7
+ desc "Build racket-mvc gem"
6
8
  task :build_gem do
7
9
  exec 'gem build racket.gemspec'
8
10
  end
9
11
 
12
+ desc "Build yard docs"
10
13
  task :doc do
11
14
  exec 'yard'
12
15
  end
13
16
 
17
+ desc "Show list of undocumented modules/classes/methods"
14
18
  task :nodoc do
15
19
  exec 'yard stats --list-undoc'
16
20
  end
17
21
 
22
+ desc "Publish racket-mvc gem"
23
+ task publish_gem: [:build_gem] do
24
+ exec 'gem push racket-mvc.gem'
25
+ end
26
+
27
+ desc "Run bacon tests"
18
28
  task :test do
19
29
  exec 'bacon spec/racket.rb'
20
30
  end
data/lib/racket.rb CHANGED
@@ -26,7 +26,7 @@ require_relative 'racket/request.rb'
26
26
  require_relative 'racket/response.rb'
27
27
  require_relative 'racket/router.rb'
28
28
  require_relative 'racket/session.rb'
29
- require_relative 'racket/view_cache.rb'
29
+ require_relative 'racket/view_manager.rb'
30
30
  require_relative 'racket/utils.rb'
31
31
 
32
32
  # Racket main namespace
@@ -66,7 +66,7 @@ module Racket
66
66
  default_action: :index,
67
67
  default_content_type: 'text/html',
68
68
  default_controller_helpers: [:routing, :view],
69
- default_layout: '_default.*',
69
+ default_layout: nil,
70
70
  default_view: nil,
71
71
  helper_dir: Utils.build_path(root_dir, 'helpers'),
72
72
  layout_dir: Utils.build_path(root_dir, 'layouts'),
@@ -202,7 +202,7 @@ module Racket
202
202
  # @return [nil]
203
203
  def self.reload
204
204
  setup_routes
205
- @view_cache = nil
205
+ @view_manager = nil
206
206
  end
207
207
 
208
208
  # Requires a file using the current application directory as a base path.
@@ -258,9 +258,9 @@ module Racket
258
258
 
259
259
  # Returns the view cache of the currently running application.
260
260
  #
261
- # @return [ViewCache]
262
- def self.view_cache
263
- @view_cache ||= ViewCache.new(@options[:layout_dir], @options[:view_dir])
261
+ # @return [Racket::ViewManager]
262
+ def self.view_manager
263
+ @view_manager ||= ViewManager.new(@options[:layout_dir], @options[:view_dir])
264
264
  end
265
265
 
266
266
  private_class_method :application, :default_options, :expand_paths, :inform, :init,
@@ -191,7 +191,7 @@ module Racket
191
191
  __run_hook(:before)
192
192
  __run_action
193
193
  __run_hook(:after)
194
- Application.view_cache.render(self)
194
+ Application.view_manager.render(self)
195
195
  end
196
196
 
197
197
  private
@@ -25,7 +25,7 @@ module Racket
25
25
  # Minor version
26
26
  MINOR = 2
27
27
  # Teeny version
28
- TEENY = 0
28
+ TEENY = 1
29
29
  # Is it a prerelease?
30
30
  PRERELEASE = false
31
31
 
@@ -0,0 +1,166 @@
1
+ # Racket - The noisy Rack MVC framework
2
+ # Copyright (C) 2015 Lars Olsson <lasso@lassoweb.se>
3
+ #
4
+ # This file is part of Racket.
5
+ #
6
+ # Racket is free software: you can redistribute it and/or modify
7
+ # it under the terms of the GNU Affero General Public License as published by
8
+ # the Free Software Foundation, either version 3 of the License, or
9
+ # (at your option) any later version.
10
+ #
11
+ # Racket is distributed in the hope that it will be useful,
12
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ # GNU Affero General Public License for more details.
15
+ #
16
+ # You should have received a copy of the GNU Affero General Public License
17
+ # along with Racket. If not, see <http://www.gnu.org/licenses/>.
18
+
19
+ require 'tilt'
20
+
21
+ module Racket
22
+ # Handles rendering in Racket applications.
23
+ class ViewManager
24
+
25
+ attr_reader :layout_cache
26
+ attr_reader :view_cache
27
+
28
+ def initialize(layout_base_dir, view_base_dir)
29
+ @layout_base_dir = layout_base_dir
30
+ @view_base_dir = view_base_dir
31
+ @layout_cache = {}
32
+ @view_cache = {}
33
+ end
34
+
35
+ # Renders a controller based on the request path and the variables set in the
36
+ # controller instance.
37
+ #
38
+ # @param [Controller] controller
39
+ # @return [Hash]
40
+ def render(controller)
41
+ template_path = get_template_path(controller)
42
+ view = get_view(template_path, controller)
43
+ if view
44
+ output = Tilt.new(view).render(controller)
45
+ layout = get_layout(template_path, controller)
46
+ output = Tilt.new(layout).render(controller) { output } if layout
47
+ else
48
+ output = controller.racket.action_result
49
+ end
50
+ controller.response.write(output)
51
+ controller.response.finish
52
+ end
53
+
54
+ private
55
+
56
+ def get_template_path(controller)
57
+ template_path = [Application.get_route(controller.class), controller.racket.action].join('/')
58
+ template_path = template_path[1..-1] if template_path.start_with?('//')
59
+ template_path
60
+ end
61
+
62
+ # Calls a template proc. Depending on how many parameters the template proc takes, different
63
+ # types of information will be passed to the proc.
64
+ # If the proc takes zero parameters, no information will be passed.
65
+ # If the proc takes one parameter, it will contain the current action.
66
+ # If the proc takes two parameters, they will contain the current action and the current params.
67
+ # If the proc takes three parameters, they will contain the current action, the current params
68
+ # and the current request.
69
+ #
70
+ # @param [Proc] proc
71
+ # @param [Racket::Controller] controller
72
+ # @return [String]
73
+ def call_template_proc(proc, controller)
74
+ possible_proc_args = [controller.racket.action, controller.racket.params, controller.request]
75
+ proc_args = []
76
+ 1.upto(proc.arity) { proc_args.push(possible_proc_args.shift) }
77
+ proc.call(*proc_args).to_s
78
+ end
79
+
80
+ # Tries to locate a layout matching +path+ in the file system and returns the path if a
81
+ # matching file is found. If no matching file is found, +nil+ is returned. The result is cached,
82
+ # meaning that the filesystem lookup for a specific path will only happen once.
83
+ #
84
+ # @param [String] path
85
+ # @param [Racket::Controller] controller
86
+ # @return [String|nil]
87
+ def get_layout(path, controller)
88
+ unless @layout_cache.key?(path)
89
+ layout = lookup_template(@layout_base_dir, path)
90
+ layout =
91
+ lookup_default_template(
92
+ @layout_base_dir, File.dirname(path), controller.controller_option(:default_layout)
93
+ ) unless layout
94
+ Application.inform_dev(
95
+ "Using layout #{layout.inspect} for #{controller.class}.#{controller.racket.action}."
96
+ )
97
+ @layout_cache[path] = layout
98
+ end
99
+ layout = @layout_cache[path]
100
+ if layout.is_a?(Proc)
101
+ layout =
102
+ lookup_template(
103
+ @layout_base_dir,
104
+ [File.dirname(path), call_template_proc(layout, controller)].join('/')
105
+ )
106
+ end
107
+ layout
108
+ end
109
+
110
+ # Tries to locate a view matching +path+ in the file system and returns the path if a
111
+ # matching file is found. If no matching file is found, +nil+ is returned. The result is cached,
112
+ # meaning that the filesystem lookup for a specific path will only happen once.
113
+ #
114
+ # @param [String] path
115
+ # @param [Racket::Controller] controller
116
+ # @return [String|nil]
117
+ def get_view(path, controller)
118
+ unless @view_cache.key?(path)
119
+ view = lookup_template(@view_base_dir, path)
120
+ view =
121
+ lookup_default_template(
122
+ @view_base_dir, File.dirname(path), controller.controller_option(:default_view)
123
+ ) unless view
124
+ Application.inform_dev(
125
+ "Using view #{view.inspect} for #{controller.class}.#{controller.racket.action}."
126
+ )
127
+ @view_cache[path] = view
128
+ end
129
+ view = @view_cache[path]
130
+ if view.is_a?(Proc)
131
+ view =
132
+ lookup_template(
133
+ @view_base_dir,
134
+ [File.dirname(path), call_template_proc(view, controller)].join('/')
135
+ )
136
+ end
137
+ view
138
+ end
139
+
140
+ def lookup_default_template(base_path, path, default)
141
+ return lookup_template(base_path, File.join(path, default.to_s)) if
142
+ default.is_a?(String) || default.is_a?(Symbol)
143
+ default
144
+ end
145
+
146
+ # Locates a file in the filesystem matching an URL path. If there exists a matching file, the
147
+ # path to it is returned. If there is no matching file, +nil+ is returned.
148
+ #
149
+ # @param [String] base_path
150
+ # @param [String] path
151
+ # @return [String|nil]
152
+ def lookup_template(base_path, path)
153
+ file_path = File.join(base_path, path)
154
+ action = File.basename(file_path)
155
+ file_path = File.dirname(file_path)
156
+ return nil unless Utils.dir_readable?(file_path)
157
+ matcher = File.extname(action).empty? ? "#{action}.*" : action
158
+ Dir.chdir(file_path) do
159
+ files = Pathname.glob(matcher)
160
+ return nil if files.empty?
161
+ final_path = File.join(file_path, files.first.to_s)
162
+ Utils.file_readable?(final_path) ? final_path : nil
163
+ end
164
+ end
165
+ end
166
+ end
data/spec/_custom.rb CHANGED
@@ -106,4 +106,16 @@ describe 'A custom Racket test Application' do
106
106
  last_response.headers.key?('Content-Disposition').should.equal(false)
107
107
  last_response.body.should.equal("Not Found")
108
108
  end
109
+
110
+ it 'should be able to handle dynamic layouts and views' do
111
+ get '/sub4/foo'
112
+ last_response.status.should.equal(200)
113
+ last_response.body.should.equal("LAYOUT: myfoo: FOO\n\n")
114
+ get '/sub4/bar'
115
+ last_response.status.should.equal(200)
116
+ last_response.body.should.equal("LAYOUT: mybar: BAR\n\n")
117
+ get '/sub4/baz'
118
+ last_response.status.should.equal(200)
119
+ last_response.body.should.equal("LAYOUT: default: BAZ\n\n")
120
+ end
109
121
  end
@@ -0,0 +1,26 @@
1
+ class CustomSubController4 < Racket::Controller
2
+
3
+ set_option :default_layout, lambda { 'layout.erb' }
4
+
5
+ set_option :default_view,
6
+ lambda { |action|
7
+ case action
8
+ when :foo then 'myfoo.erb'
9
+ when :bar then 'mybar.erb'
10
+ else 'default.erb'
11
+ end
12
+ }
13
+
14
+ def foo
15
+ @data = 'FOO'
16
+ end
17
+
18
+ def bar
19
+ @data = 'BAR'
20
+ end
21
+
22
+ def baz
23
+ @data = 'BAZ'
24
+ end
25
+
26
+ end
@@ -0,0 +1 @@
1
+ LAYOUT: <%=yield%>
@@ -0,0 +1 @@
1
+ default: <%=@data%>
@@ -0,0 +1 @@
1
+ mybar: <%=@data%>
@@ -0,0 +1 @@
1
+ myfoo: <%=@data%>
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: racket-mvc
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Lars Olsson
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-08-21 00:00:00.000000000 Z
11
+ date: 2015-08-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: http_router
@@ -158,7 +158,7 @@ files:
158
158
  - lib/racket/session.rb
159
159
  - lib/racket/utils.rb
160
160
  - lib/racket/version.rb
161
- - lib/racket/view_cache.rb
161
+ - lib/racket/view_manager.rb
162
162
  - spec/_custom.rb
163
163
  - spec/_default.rb
164
164
  - spec/_invalid.rb
@@ -168,12 +168,17 @@ files:
168
168
  - spec/test_custom_app/controllers/sub2/custom_sub_controller_2.rb
169
169
  - spec/test_custom_app/controllers/sub3/custom_sub_controller_3.rb
170
170
  - spec/test_custom_app/controllers/sub3/inherited/custom_inherited_controller.rb
171
+ - spec/test_custom_app/controllers/sub4/default_sub_controller_4.rb
171
172
  - spec/test_custom_app/extra/blob.rb
172
173
  - spec/test_custom_app/extra/blob/inner_blob.rb
173
174
  - spec/test_custom_app/files/plain_text.txt
174
175
  - spec/test_custom_app/files/secret.erb
175
176
  - spec/test_custom_app/layouts/sub2/zebra.erb
177
+ - spec/test_custom_app/layouts/sub4/layout.erb
176
178
  - spec/test_custom_app/templates/sub2/template.erb
179
+ - spec/test_custom_app/templates/sub4/default.erb
180
+ - spec/test_custom_app/templates/sub4/mybar.erb
181
+ - spec/test_custom_app/templates/sub4/myfoo.erb
177
182
  - spec/test_default_app/controllers/default_root_controller.rb
178
183
  - spec/test_default_app/controllers/sub1/default_sub_controller_1.rb
179
184
  - spec/test_default_app/controllers/sub2/default_sub_controller_2.rb
@@ -200,7 +205,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
200
205
  version: '0'
201
206
  requirements: []
202
207
  rubyforge_project:
203
- rubygems_version: 2.4.7
208
+ rubygems_version: 2.4.8
204
209
  signing_key:
205
210
  specification_version: 4
206
211
  summary: Racket - The noisy Rack MVC framework
@@ -1,107 +0,0 @@
1
- # Racket - The noisy Rack MVC framework
2
- # Copyright (C) 2015 Lars Olsson <lasso@lassoweb.se>
3
- #
4
- # This file is part of Racket.
5
- #
6
- # Racket is free software: you can redistribute it and/or modify
7
- # it under the terms of the GNU Affero General Public License as published by
8
- # the Free Software Foundation, either version 3 of the License, or
9
- # (at your option) any later version.
10
- #
11
- # Racket is distributed in the hope that it will be useful,
12
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
- # GNU Affero General Public License for more details.
15
- #
16
- # You should have received a copy of the GNU Affero General Public License
17
- # along with Racket. If not, see <http://www.gnu.org/licenses/>.
18
-
19
- require 'tilt'
20
-
21
- module Racket
22
- # Handles rendering in Racket applications.
23
- class ViewCache
24
- def initialize(layout_base_dir, template_base_dir)
25
- @layout_base_dir = layout_base_dir
26
- @template_base_dir = template_base_dir
27
- @layouts_by_path = {}
28
- @templates_by_path = {}
29
- end
30
-
31
- # Renders a controller based on the request path and the variables set in the
32
- # controller instance.
33
- #
34
- # @param [Controller] controller
35
- # @return [Hash]
36
- def render(controller)
37
- template_path = [Application.get_route(controller.class), controller.racket.action].join('/')
38
- template_path = template_path[1..-1] if template_path.start_with?('//')
39
- template =
40
- find_template(template_path, controller.controller_option(:default_view))
41
- if template
42
- output = Tilt.new(template).render(controller)
43
- layout =
44
- find_layout(template_path, controller.controller_option(:default_layout))
45
- output = Tilt.new(layout).render(controller) { output } if layout
46
- else
47
- output = controller.racket.action_result
48
- end
49
- controller.response.write(output)
50
- controller.response.finish
51
- end
52
-
53
- private
54
-
55
- # Tries to locate a layout matching +url_path+ in the file system and returns the path if a
56
- # matching file is found. If no matching file is found, +nil+ is returned. The result is
57
- # cached, meaning that the filesystem lookup for a specific url_path will only happen once.
58
- #
59
- # @param [String] url_path
60
- # @param [String|nil] default_layout
61
- # @return [String|nil]
62
- def find_layout(url_path, default_layout)
63
- return @layouts_by_path[url_path] if @layouts_by_path.key?(url_path)
64
- @layouts_by_path[url_path] = find_matching_file(@layout_base_dir, url_path, default_layout)
65
- end
66
-
67
- # Tries to locate a template matching +url_path+ in the file system and returns the path if a
68
- # matching file is found. If no matching file is found, +nil+ is returned. The result is
69
- # cached, meaning that the filesystem lookup for a specific url_path will only happen once.
70
- #
71
- # @param [String] url_path
72
- # @param [String|nil] default_view
73
- # @return [String|nil]
74
- def find_template(url_path, default_view)
75
- return @templates_by_path[url_path] if @templates_by_path.key?(url_path)
76
- @templates_by_path[url_path] = find_matching_file(@template_base_dir, url_path, default_view)
77
- end
78
-
79
- # Locates a file in the filesystem matching an URL path. If there exists a matching file, the
80
- # path to it is returned. If there is no matching file, +nil+ is returned.
81
- #
82
- # @param [String] base_file_path
83
- # @param [String] url_path
84
- # @param [String|nil] default_file
85
- # @return [String|nil]
86
- def find_matching_file(base_file_path, url_path, default_file)
87
- file_path = File.join(base_file_path, url_path)
88
- action = File.basename(file_path)
89
- file_path = File.dirname(file_path)
90
- return nil unless Utils.dir_readable?(file_path)
91
- Dir.chdir(file_path) do
92
- files = Pathname.glob("#{action}.*")
93
- if files.empty?
94
- if default_file
95
- files = Pathname.glob(default_file)
96
- return nil if files.empty? # No default file found
97
- final_path = File.join(file_path, files.first.to_s)
98
- return Utils.file_readable?(final_path) ? final_path : nil
99
- end
100
- return nil # Neither default file or specified file found
101
- end
102
- final_path = File.join(file_path, files.first.to_s)
103
- return Utils.file_readable?(final_path) ? final_path : nil
104
- end
105
- end
106
- end
107
- end