racket-mvc 0.2.0 → 0.2.1

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.
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