racket-mvc 0.2.1 → 0.2.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 29d1cf6f2b573f99dc79d38f46c61bbc877b81c6
4
- data.tar.gz: 114fceb1c2ff59e31a94b1300c1efbad34fc78cc
3
+ metadata.gz: 105b08877782c44a513558312f3e9b6af7daef75
4
+ data.tar.gz: 4ccd48feacc8788667f1ea5ab580a3cdb17cbdb0
5
5
  SHA512:
6
- metadata.gz: fb0558de22c5ed965ea8955caa8aac5309cadaa4ed80f01d08cce38666575f3715bd3a84dd1d6e005d94aa191cc433cd5a123cf73169cfba005b9497094f7aff
7
- data.tar.gz: b1b51dc4dcf51d057d472f1897b0e9cd92be66dad8abe06fe9eb7127bedc8e0122d3a58787acc2aee77027831abb0bbcab82bbff1bb85e64191675908062da0e
6
+ metadata.gz: 7275ee4175f164a783c9f827ddaee45f68b949ac4977c3637f6ff80e6f7662d03f0985926872d8fa68b68d4f1fa91a34c8aca3d2e3c8383cdbbdb9f3f4d45bac
7
+ data.tar.gz: 6795e2bfcca8c5671df6e65012fc60ec6ab374458d074c69f91451f9d5fde72de257530c9c32cf0e9336b16f18bc20417a2f6339edeefd09dbba91f62c5a3ab8
data/README.md CHANGED
@@ -1,49 +1,49 @@
1
- # Racket - The noisy Rack MVC framework
2
-
3
- [![Build Status](https://travis-ci.org/lasso/racket.svg?branch=master)](https://travis-ci.org/lasso/racket)    [![codecov.io](https://codecov.io/github/lasso/racket/coverage.svg?branch=master)](https://codecov.io/github/lasso/racket?branch=master)    [![Gem Version](https://badge.fury.io/rb/racket-mvc.svg)](http://badge.fury.io/rb/racket-mvc)
4
-
5
- ## Say what?
6
- Yes. It is yet another framework built on rack. Using MVC. Doing silly stuff while you look the other way.
7
-
8
- ## Why? I though there were a gazillion frameworks that did the same thing already...
9
- You are correct. There are _lots_ of Rack frameworks out there. This one does not pretend to do anything special
10
- that you could not get from any of them.
11
-
12
- ## So, I have to ask again. Why did you create this monstrosity?
13
- Well, when my web host suddenly started insisting on using Phusion Passenger on all of their servers
14
- I needed to replace my old [Ramaze](http://ramaze.net/) setup without to much hassle. I tried several
15
- other Rack framework, but none of them seemed capable of replacing my apps without some major rewrites.
16
-
17
- ## So you just though writing a whole new framework would be easier than using Rails?
18
- Yes. Writing Rack frameworks is easy! And since I am able to decide exactly what features I want I don't
19
- need to adopt to a large ecosystem of concepts I do not like.
20
-
21
- ## So, is it any good?
22
- Let us just say it is good _enough_ for my needs at the moment. I plan to add more features/make stuff faster
23
- whenever I am finished porting most of my old apps from Ramaze.
24
-
25
- ## Where are the tests?
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
-
28
- - ruby 1.9.3
29
- - ruby 2.0.0
30
- - ruby 2.1.7
31
- - ruby 2.2.3
32
- - jruby 1.7 (1.9 mode only)
33
- - jruby 9.0.0.0
34
- - rbx-2 (latest version)
35
-
36
- I am using [bacon](https://github.com/chneukirchen/bacon) and [rack-test](https://github.com/brynary/rack-test) for testing. Run the tests by typing `rake test`in the root directory. Code coverage reports are provided by [simplecov](https://rubygems.org/gems/simplecov). After the tests have run the an HTML report can be found in the `coverage` directory.
37
-
38
- If you are not interested in running the tests yourself you could have a look at the test status at [Travis CI](https://travis-ci.org/lasso/racket) and the code coverage at [Codecov](https://codecov.io/github/lasso/racket). Their stats get updated on every commit.
39
-
40
- ## Alright, I want to try using this stuff. Where are the docs?
41
- At the moment there is not much documentation available, but I have started working on the [wiki](https://github.com/lasso/racket/wiki).
42
-
43
- The code itself is documented using [Yard](http://yardoc.org/). The docs are not generated automatically, you need to run `rake doc` in the root directory to generate them. After running the rake task the documentation will be available in the `doc` directory.
44
-
45
- ## Why is the code licenced under the GNU Affero General Public License? I want a more liberal licence!
46
- Because I think it is a Good Thing™ to share code. The
47
- [GNU Affero General Public License licence](https://www.gnu.org/licenses/agpl.html) is very liberal unless you plan
48
- on beeing egotistical. I you feel you cannot work with that, please choose
49
- [something else](https://en.wikipedia.org/wiki/Comparison_of_web_application_frameworks#Ruby).
1
+ # Racket - The noisy Rack MVC framework
2
+
3
+ [![Build Status](https://travis-ci.org/lasso/racket.svg?branch=master)](https://travis-ci.org/lasso/racket)    [![Code Climate](https://codeclimate.com/github/lasso/racket/badges/gpa.svg)](https://codeclimate.com/github/lasso/racket)    [![codecov.io](https://codecov.io/github/lasso/racket/coverage.svg?branch=master)](https://codecov.io/github/lasso/racket?branch=master)    [![Gem Version](https://badge.fury.io/rb/racket-mvc.svg)](http://badge.fury.io/rb/racket-mvc)
4
+
5
+ ## Say what?
6
+ Yes. It is yet another framework built on rack. Using MVC. Doing silly stuff while you look the other way.
7
+
8
+ ## Why? I though there were a gazillion frameworks that did the same thing already...
9
+ You are correct. There are _lots_ of Rack frameworks out there. This one does not pretend to do anything special
10
+ that you could not get from any of them.
11
+
12
+ ## So, I have to ask again. Why did you create this monstrosity?
13
+ Well, when my web host suddenly started insisting on using Phusion Passenger on all of their servers
14
+ I needed to replace my old [Ramaze](http://ramaze.net/) setup without to much hassle. I tried several
15
+ other Rack framework, but none of them seemed capable of replacing my apps without some major rewrites.
16
+
17
+ ## So you just though writing a whole new framework would be easier than using Rails?
18
+ Yes. Writing Rack frameworks is easy! And since I am able to decide exactly what features I want I don't
19
+ need to adopt to a large ecosystem of concepts I do not like.
20
+
21
+ ## So, is it any good?
22
+ Let us just say it is good _enough_ for my needs at the moment. I plan to add more features/make stuff faster
23
+ whenever I am finished porting most of my old apps from Ramaze.
24
+
25
+ ## Where are the tests?
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
+
28
+ - 1.9.3
29
+ - 2.0.0
30
+ - 2.1.7
31
+ - 2.2.3
32
+ - jruby-19mode
33
+ - jruby-head
34
+ - rbx-2
35
+
36
+ I am using [bacon](https://github.com/chneukirchen/bacon) and [rack-test](https://github.com/brynary/rack-test) for testing. Run the tests by typing `rake test`in the root directory. Code coverage reports are provided by [simplecov](https://rubygems.org/gems/simplecov). After the tests have run the an HTML report can be found in the `coverage` directory.
37
+
38
+ If you are not interested in running the tests yourself you could have a look at the test status at [Travis CI](https://travis-ci.org/lasso/racket) and the code coverage at [Codecov](https://codecov.io/github/lasso/racket). Their stats get updated on every commit.
39
+
40
+ ## Alright, I want to try using this stuff. Where are the docs?
41
+ At the moment there is not much documentation available, but I have started working on the [wiki](https://github.com/lasso/racket/wiki).
42
+
43
+ The code itself is documented using [Yard](http://yardoc.org/). The docs are not generated automatically, you need to run `rake doc` in the root directory to generate them. After running the rake task the documentation will be available in the `doc` directory.
44
+
45
+ ## Why is the code licenced under the GNU Affero General Public License? I want a more liberal licence!
46
+ Because I think it is a Good Thing™ to share code. The
47
+ [GNU Affero General Public License licence](https://www.gnu.org/licenses/agpl.html) is very liberal unless you plan
48
+ on beeing egotistical. I you feel you cannot work with that, please choose
49
+ [something else](https://en.wikipedia.org/wiki/Comparison_of_web_application_frameworks#Ruby).
data/Rakefile CHANGED
@@ -1,30 +1,31 @@
1
1
  require 'rubygems'
2
2
  require 'bundler/setup'
3
+ require './rake/utils.rb'
3
4
 
4
- desc "Run bacon tests"
5
+ desc 'Run bacon tests'
5
6
  task default: [:test]
6
7
 
7
- desc "Build racket-mvc gem"
8
+ desc 'Build racket-mvc gem'
8
9
  task :build_gem do
9
10
  exec 'gem build racket.gemspec'
10
11
  end
11
12
 
12
- desc "Build yard docs"
13
+ desc 'Build yard docs'
13
14
  task :doc do
14
15
  exec 'yard'
15
16
  end
16
17
 
17
- desc "Show list of undocumented modules/classes/methods"
18
+ desc 'Show list of undocumented modules/classes/methods'
18
19
  task :nodoc do
19
20
  exec 'yard stats --list-undoc'
20
21
  end
21
22
 
22
- desc "Publish racket-mvc gem"
23
+ desc 'Publish racket-mvc gem'
23
24
  task publish_gem: [:build_gem] do
24
- exec 'gem push racket-mvc.gem'
25
+ exec "gem push racket-mvc#{racket_version}.gem"
25
26
  end
26
27
 
27
- desc "Run bacon tests"
28
+ desc 'Run bacon tests'
28
29
  task :test do
29
30
  exec 'bacon spec/racket.rb'
30
31
  end
@@ -24,24 +24,17 @@ module Racket
24
24
  helper_modules = {}
25
25
  helpers.each do |helper|
26
26
  helper_module = helper.to_s.split('_').collect(&:capitalize).join.to_sym
27
- begin
28
- begin
29
- require "racket/helpers/#{helper}"
30
- rescue LoadError
31
- if helper_dir
32
- begin
33
- require Utils.build_path(helper_dir, helper)
34
- rescue LoadError
35
- end
36
- end
37
- end
27
+ Utils.run_block(NameError) do
28
+ Utils.run_block(LoadError) { require "racket/helpers/#{helper}" } ||
29
+ (helper_dir &&
30
+ Utils.run_block(LoadError) { require Utils.build_path(helper_dir, helper) }
31
+ )
38
32
  helper_modules[helper] = Racket::Helpers.const_get(helper_module)
39
33
  Application.inform_dev("Added helper module #{helper.inspect} to class #{self}.")
40
- rescue NameError
34
+ end ||
41
35
  Application.inform_dev(
42
36
  "Failed to add helper module #{helper.inspect} to class #{self}.", :warn
43
37
  )
44
- end
45
38
  end
46
39
  helper_modules
47
40
  end
@@ -102,7 +95,7 @@ module Racket
102
95
  helper_modules.merge!(__load_helpers(existing_helpers))
103
96
  end
104
97
  # Load new helpers
105
- helpers.map! { |helper| helper.to_sym }
98
+ helpers.map!(&:to_sym)
106
99
  helpers.reject! { |helper| helper_modules.key?(helper) }
107
100
  helper_modules.merge!(__load_helpers(helpers))
108
101
  set_option(:helpers, helper_modules)
@@ -35,17 +35,25 @@ module Racket
35
35
  # @return [Module] A module encapsulating all state relating to the current request
36
36
  def self.init(env, klass, action, params)
37
37
  klass.helper if klass.get_option(:helpers).nil? # Makes sure default helpers are loaded.
38
- racket = State.new(action, nil, params)
39
- request = Request.new(env)
40
- response = Response.new
41
- session = Session.new(env['rack.session']) if env.key?('rack.session')
38
+ properties = init_properties(action, params, env)
42
39
  Module.new do
43
40
  klass.get_option(:helpers).each_value { |helper| include helper }
44
- define_method(:racket) { racket }
45
- define_method(:request) { request }
46
- define_method(:response) { response }
47
- define_method(:session) { session } if env.key?('rack.session')
41
+ properties.each_pair { |key, value| define_method(key) { value } }
48
42
  end
49
43
  end
44
+
45
+ def self.init_properties(action, params, env)
46
+ properties =
47
+ {
48
+ racket: State.new(action, nil, params),
49
+ request: Request.new(env),
50
+ response: Response.new
51
+ }
52
+ session = env.fetch('rack.session', nil)
53
+ properties[:session] = Session.new(session) if session
54
+ properties
55
+ end
56
+
57
+ private_class_method :init_properties
50
58
  end
51
59
  end
@@ -28,12 +28,7 @@ module Racket
28
28
  # @return [Array]
29
29
  def send_file(file, options = {})
30
30
  file = Utils.build_path(file)
31
- # Respond with a 404 Not Found if the file cannot be read.
32
- respond!(
33
- 404,
34
- { 'Content-Type' => 'text/plain' },
35
- Rack::Utils::HTTP_STATUS_CODES[404]
36
- ) unless Utils.file_readable? (file)
31
+ _send_file_check_file_readable(file)
37
32
  headers = {}
38
33
  mime_type = options.fetch(:mime_type, nil)
39
34
  # Calculate MIME type if it was not already specified.
@@ -41,15 +36,28 @@ module Racket
41
36
  headers['Content-Type'] = mime_type
42
37
  # Set Content-Disposition (and a file name) if the file should be downloaded
43
38
  # instead of displayed inline.
44
- if options.fetch(:download, false)
45
- filename = options.fetch(:filename, nil).to_s
46
- headers['Content-Disposition'] = 'attachment'
47
- headers['Content-Disposition'] << sprintf('; filename="%s"', filename) unless
48
- filename.empty?
49
- end
39
+ _send_file_set_content_disposition(options, headers)
50
40
  # Send response
51
41
  respond!(200, headers, ::File.read(file))
52
42
  end
43
+
44
+ private
45
+
46
+ def _send_file_check_file_readable(file)
47
+ # Respond with a 404 Not Found if the file cannot be read.
48
+ respond!(
49
+ 404,
50
+ { 'Content-Type' => 'text/plain' },
51
+ Rack::Utils::HTTP_STATUS_CODES[404]
52
+ ) unless Utils.file_readable?(file)
53
+ end
54
+
55
+ def _send_file_set_content_disposition(options, headers)
56
+ return unless options.fetch(:download, false)
57
+ filename = options.fetch(:filename, nil).to_s
58
+ headers['Content-Disposition'] = 'attachment'
59
+ headers['Content-Disposition'] << format('; filename="%s"', filename) unless filename.empty?
60
+ end
53
61
  end
54
62
  end
55
63
  end
data/lib/racket/router.rb CHANGED
@@ -23,38 +23,41 @@ require 'http_router'
23
23
  module Racket
24
24
  # Handles routing in Racket applications.
25
25
  class Router
26
+ attr_reader :action_cache
27
+ attr_reader :routes
28
+
26
29
  def initialize
27
30
  @router = HttpRouter.new
28
- @routes_by_controller = {}
29
- @actions_by_controller = {}
31
+ @routes = {}
32
+ @action_cache = {}
30
33
  end
31
34
 
32
35
  # Caches available actions for each controller class. This also works for controller classes
33
36
  # that inherit from other controller classes.
34
37
  #
35
- # @param [Class] controller
38
+ # @param [Class] controller_class
36
39
  # @return [nil]
37
- def cache_actions(controller)
40
+ def cache_actions(controller_class)
38
41
  actions = SortedSet.new
39
- current = controller
40
- while current < Controller
41
- actions.merge(current.instance_methods(false))
42
- current = current.superclass
42
+ current_class = controller_class
43
+ while current_class < Controller
44
+ actions.merge(current_class.public_instance_methods(false))
45
+ current_class = current_class.superclass
43
46
  end
44
- (@actions_by_controller[controller] = actions.to_a) && nil
47
+ (@action_cache[controller_class] = actions.to_a) && nil
45
48
  end
46
49
 
47
50
  # Returns a route to the specified controller/action/parameter combination.
48
51
  #
49
- # @param [Class] controller
52
+ # @param [Class] controller_class
50
53
  # @param [Symbol] action
51
54
  # @param [Array] params
52
55
  # @return [String]
53
- def get_route(controller, action, params)
54
- fail "Cannot find controller #{controller}" unless @routes_by_controller.key?(controller)
56
+ def get_route(controller_class, action, params)
57
+ fail "Cannot find controller #{controller_class}" unless @routes.key?(controller_class)
55
58
  params.flatten!
56
59
  route = ''
57
- route << @routes_by_controller[controller]
60
+ route << @routes[controller_class]
58
61
  route << "/#{action}" unless action.nil?
59
62
  route << "/#{params.join('/')}" unless params.empty?
60
63
  route = route[1..-1] if route.start_with?('//') # Special case for root path
@@ -64,14 +67,14 @@ module Racket
64
67
  # Maps a controller to the specified path.
65
68
  #
66
69
  # @param [String] path
67
- # @param [Class] controller
70
+ # @param [Class] controller_class
68
71
  # @return [nil]
69
- def map(path, controller)
70
- controller_base_path = path.empty? ? '/' : path
71
- Application.inform_dev("Mapping #{controller} to #{controller_base_path}.")
72
- @router.add("#{path}(/*params)").to(controller)
73
- @routes_by_controller[controller] = controller_base_path
74
- cache_actions(controller) && nil
72
+ def map(path, controller_class)
73
+ controller_class_base_path = path.empty? ? '/' : path
74
+ Application.inform_dev("Mapping #{controller_class} to #{controller_class_base_path}.")
75
+ @router.add("#{path}(/*params)").to(controller_class)
76
+ @routes[controller_class] = controller_class_base_path
77
+ cache_actions(controller_class) && nil
75
78
  end
76
79
 
77
80
  # @todo: Allow the user to set custom handlers for different errors
@@ -105,7 +108,7 @@ module Racket
105
108
  action = params.empty? ? target_klass.get_option(:default_action) : params.shift.to_sym
106
109
 
107
110
  # Check if action is available on target
108
- return render_error(404) unless @actions_by_controller[target_klass].include?(action)
111
+ return render_error(404) unless @action_cache[target_klass].include?(action)
109
112
 
110
113
  # Rewrite PATH_INFO to reflect that we split out the parameters
111
114
  env['PATH_INFO'] = env['PATH_INFO']
data/lib/racket/utils.rb CHANGED
@@ -19,6 +19,38 @@
19
19
  module Racket
20
20
  # Collects utilities needed by different objects in Racket.
21
21
  class Utils
22
+ # Handles exceptions dynamically
23
+ class ExceptionHandler
24
+ # Runs a block.
25
+ # If no exceptions are raised, this method returns true.
26
+ # If any of the provided error types are raised, this method returns false.
27
+ # If any other exception is raised, this method will just forward the exception.
28
+ #
29
+ # @param [Array] errors
30
+ # @return [true|flase]
31
+ def self.run_block(errors)
32
+ fail 'Need a block' unless block_given?
33
+ begin
34
+ true.tap { yield }
35
+ rescue boolean_module(errors)
36
+ false
37
+ end
38
+ end
39
+
40
+ # Returns an anonymous module that can be used to rescue exceptions dynamically.
41
+ def self.boolean_module(errors)
42
+ Module.new do
43
+ (class << self; self; end).instance_eval do
44
+ define_method(:===) do |error|
45
+ errors.any? { |e| error.class <= e }
46
+ end
47
+ end
48
+ end
49
+ end
50
+
51
+ private_class_method :boolean_module
52
+ end
53
+
22
54
  # Builds and returns a path in the file system from the provided arguments. The first element
23
55
  # in the argument list can be either absolute or relative, all other arguments must be relative,
24
56
  # otherwise they will be removed from the final path.
@@ -29,7 +61,7 @@ module Racket
29
61
  if args.empty?
30
62
  path = Pathname.pwd
31
63
  else
32
- args.map! { |arg| arg.to_s }
64
+ args.map!(&:to_s)
33
65
  path = Pathname.new(args.shift)
34
66
  path = Pathname.new(Application.options[:root_dir]).join(path) if path.relative?
35
67
  args.each do |arg|
@@ -50,5 +82,16 @@ module Racket
50
82
  pathname = Pathname.new(path)
51
83
  pathname.exist? && pathname.file? && pathname.readable?
52
84
  end
85
+
86
+ # Runs a block.
87
+ # If no exceptions are raised, this method returns true.
88
+ # If any of the provided error types are raised, this method returns false.
89
+ # If any other exception is raised, this method will just forward the exception.
90
+ #
91
+ # @param [Array] errors
92
+ # @return [true|flase]
93
+ def self.run_block(*errors, &block)
94
+ ExceptionHandler.run_block(errors, &block)
95
+ end
53
96
  end
54
97
  end
@@ -25,7 +25,7 @@ module Racket
25
25
  # Minor version
26
26
  MINOR = 2
27
27
  # Teeny version
28
- TEENY = 1
28
+ TEENY = 2
29
29
  # Is it a prerelease?
30
30
  PRERELEASE = false
31
31
 
@@ -21,7 +21,6 @@ require 'tilt'
21
21
  module Racket
22
22
  # Handles rendering in Racket applications.
23
23
  class ViewManager
24
-
25
24
  attr_reader :layout_cache
26
25
  attr_reader :view_cache
27
26
 
@@ -77,6 +76,26 @@ module Racket
77
76
  proc.call(*proc_args).to_s
78
77
  end
79
78
 
79
+ # Returns a cached template. If the template has not been cached yet, this method will run a
80
+ # lookup against the provided parameters.
81
+ #
82
+ # @param [String] path
83
+ # @param [Racket::Controller] controller
84
+ # @param [Symbol] type
85
+ def ensure_in_cache(path, controller, type)
86
+ store = instance_variable_get("@#{type}_cache".to_sym)
87
+ return store[path] if store.key?(path)
88
+ base_dir = instance_variable_get("@#{type}_base_dir".to_sym)
89
+ default_template = controller.controller_option("default_#{type}".to_sym)
90
+ template = lookup_template(base_dir, path)
91
+ template =
92
+ lookup_default_template(base_dir, File.dirname(path), default_template) unless template
93
+ Application.inform_dev(
94
+ "Using #{type} #{template.inspect} for #{controller.class}.#{controller.racket.action}."
95
+ )
96
+ store[path] = template
97
+ end
98
+
80
99
  # Tries to locate a layout matching +path+ in the file system and returns the path if a
81
100
  # matching file is found. If no matching file is found, +nil+ is returned. The result is cached,
82
101
  # meaning that the filesystem lookup for a specific path will only happen once.
@@ -85,18 +104,7 @@ module Racket
85
104
  # @param [Racket::Controller] controller
86
105
  # @return [String|nil]
87
106
  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]
107
+ layout = ensure_in_cache(path, controller, :layout)
100
108
  if layout.is_a?(Proc)
101
109
  layout =
102
110
  lookup_template(
@@ -115,18 +123,7 @@ module Racket
115
123
  # @param [Racket::Controller] controller
116
124
  # @return [String|nil]
117
125
  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]
126
+ view = ensure_in_cache(path, controller, :view)
130
127
  if view.is_a?(Proc)
131
128
  view =
132
129
  lookup_template(
data/rake/utils.rb ADDED
@@ -0,0 +1,36 @@
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
+ def racket_version
20
+ mod = Module.new
21
+ mod.module_eval(
22
+ File.read(
23
+ File.join(File.dirname(File.dirname(__FILE__)), 'lib', 'racket', 'version.rb')
24
+ )
25
+ )
26
+ mod::Racket::Version.current
27
+ end
28
+
29
+ def racket_files
30
+ Dir.chdir(File.dirname(File.dirname(__FILE__))) do
31
+ files = FileList['lib/**/*.rb'].to_a
32
+ files.concat(FileList['rake/**/*'].to_a)
33
+ files.concat(FileList['spec/**/*'].to_a)
34
+ files.concat(FileList['COPYING.AGPL', 'Rakefile', 'README.md'].to_a)
35
+ end
36
+ end
data/spec/_custom.rb CHANGED
@@ -50,14 +50,14 @@ describe 'A custom Racket test Application' do
50
50
  last_response.headers.key?('X-Hook-Action').should.equal(true)
51
51
  last_response.headers['X-Hook-Action'].should.equal('run')
52
52
  response = JSON.parse(last_response.body)
53
- response.should.equal(["Data added in before block", "Data added in action"])
53
+ response.should.equal(['Data added in before block', 'Data added in action'])
54
54
  end
55
55
 
56
56
  it 'should let Rack::ShowExceptions handle the error' do
57
57
  get '/sub1/epic_fail'
58
58
  last_response.status.should.equal(500)
59
59
  last_response.headers['Content-Type'].should.equal('text/plain')
60
- last_response.body.should.match(%r(^RuntimeError: Epic fail!))
60
+ last_response.body.should.match(/^RuntimeError: Epic fail!/)
61
61
  end
62
62
 
63
63
  it 'should be able to render custom files' do
@@ -104,7 +104,7 @@ describe 'A custom Racket test Application' do
104
104
  last_response.status.should.equal(404)
105
105
  last_response.headers['Content-Type'].should.equal('text/plain')
106
106
  last_response.headers.key?('Content-Disposition').should.equal(false)
107
- last_response.body.should.equal("Not Found")
107
+ last_response.body.should.equal('Not Found')
108
108
  end
109
109
 
110
110
  it 'should be able to handle dynamic layouts and views' do
data/spec/_default.rb CHANGED
@@ -10,33 +10,27 @@ describe 'A default Racket test Application' do
10
10
  end
11
11
 
12
12
  it 'has mapped controllers correctly' do
13
- routes_by_controller = actions_by_controller = nil
14
- app.instance_eval do
15
- router.instance_eval do
16
- routes_by_controller = @routes_by_controller
17
- actions_by_controller = @actions_by_controller
18
- end
19
- end
20
-
21
- routes_by_controller[DefaultRootController].should.equal('/')
22
- routes_by_controller[DefaultSubController1].should.equal('/sub1')
23
- routes_by_controller[DefaultSubController2].should.equal('/sub2')
24
- routes_by_controller[DefaultSubController3].should.equal('/sub3')
25
- routes_by_controller[DefaultInheritedController].should.equal('/sub3/inherited')
26
-
27
- actions_by_controller[DefaultRootController].length.should.equal(5)
28
- actions_by_controller[DefaultRootController].include?(:index).should.equal(true)
29
- actions_by_controller[DefaultRootController].include?(:my_first_route).should.equal(true)
30
- actions_by_controller[DefaultRootController].include?(:my_second_route).should.equal(true)
31
- actions_by_controller[DefaultSubController1].length.should.equal(4)
32
- actions_by_controller[DefaultSubController1].include?(:route_to_root).should.equal(true)
33
- actions_by_controller[DefaultSubController1].include?(:route_to_nonexisting).should.equal(true)
34
- actions_by_controller[DefaultSubController2].length.should.equal(5)
35
- actions_by_controller[DefaultSubController2].include?(:index).should.equal(true)
36
- actions_by_controller[DefaultSubController2].include?(:current_action).should.equal(true)
37
- actions_by_controller[DefaultSubController2].include?(:current_params).should.equal(true)
38
- actions_by_controller[DefaultSubController3].should.equal([:index])
39
- actions_by_controller[DefaultInheritedController].should.equal([:index])
13
+ app.router.routes.length.should.equal(5)
14
+ app.router.routes[DefaultRootController].should.equal('/')
15
+ app.router.routes[DefaultSubController1].should.equal('/sub1')
16
+ app.router.routes[DefaultSubController2].should.equal('/sub2')
17
+ app.router.routes[DefaultSubController3].should.equal('/sub3')
18
+ app.router.routes[DefaultInheritedController].should.equal('/sub3/inherited')
19
+
20
+ app.router.action_cache[DefaultRootController].length.should.equal(5)
21
+ app.router.action_cache[DefaultRootController].include?(:index).should.equal(true)
22
+ app.router.action_cache[DefaultRootController].include?(:my_first_route).should.equal(true)
23
+ app.router.action_cache[DefaultRootController].include?(:my_second_route).should.equal(true)
24
+ app.router.action_cache[DefaultSubController1].length.should.equal(4)
25
+ app.router.action_cache[DefaultSubController1].include?(:route_to_root).should.equal(true)
26
+ app.router.action_cache[DefaultSubController1].include?(:route_to_nonexisting)
27
+ .should.equal(true)
28
+ app.router.action_cache[DefaultSubController2].length.should.equal(5)
29
+ app.router.action_cache[DefaultSubController2].include?(:index).should.equal(true)
30
+ app.router.action_cache[DefaultSubController2].include?(:current_action).should.equal(true)
31
+ app.router.action_cache[DefaultSubController2].include?(:current_params).should.equal(true)
32
+ app.router.action_cache[DefaultSubController3].should.equal([:index])
33
+ app.router.action_cache[DefaultInheritedController].should.equal([:index])
40
34
  end
41
35
 
42
36
  it 'should set rack variables correctly' do
@@ -46,7 +40,7 @@ describe 'A default Racket test Application' do
46
40
 
47
41
  get '/sub2/current_params/foo/bar/baz'
48
42
  last_response.status.should.equal(200)
49
- JSON.parse(last_response.body).should.equal(['foo', 'bar', 'baz'])
43
+ JSON.parse(last_response.body).should.equal(%w(foo bar baz))
50
44
  end
51
45
 
52
46
  it 'returns the correct respnse when calling index action' do
@@ -107,27 +101,27 @@ describe 'A default Racket test Application' do
107
101
  end
108
102
 
109
103
  it 'should be able to log messages to everybody' do
110
- _logger = app.options[:logger]
104
+ original_logger = app.options[:logger]
111
105
  sio = StringIO.new
112
106
  app.options[:logger] = Logger.new(sio)
113
- app.inform_all('Informational message');
107
+ app.inform_all('Informational message')
114
108
  sio.string.should.match(/Informational message/)
115
- app.options[:logger] = _logger
109
+ app.options[:logger] = original_logger
116
110
  end
117
111
 
118
112
  it 'should be able to log messages to developer' do
119
- _logger = app.options[:logger]
120
- _mode = app.options[:mode]
113
+ original_logger = app.options[:logger]
114
+ original_mode = app.options[:mode]
121
115
  sio = StringIO.new
122
116
  app.options[:logger] = Logger.new(sio)
123
117
  app.options[:mode] = :live
124
- app.inform_dev('Development message');
118
+ app.inform_dev('Development message')
125
119
  sio.string.should.be.empty
126
120
  app.options[:mode] = :dev
127
- app.inform_dev('Hey, listen up!');
128
- sio.string.should.match(%r(Hey, listen up!))
129
- app.options[:mode] = _mode
130
- app.options[:logger] = _logger
121
+ app.inform_dev('Hey, listen up!')
122
+ sio.string.should.match(/Hey, listen up!/)
123
+ app.options[:mode] = original_mode
124
+ app.options[:logger] = original_logger
131
125
  end
132
126
 
133
127
  it 'should be able to set and clear session variables' do
@@ -138,7 +132,7 @@ describe 'A default Racket test Application' do
138
132
  response.keys.should.be.empty
139
133
  get '/session_as_json?foo=bar'
140
134
  last_response.headers.keys.should.include('Set-Cookie')
141
- last_response.headers['Set-Cookie'].should.match(%r(racket.session=))
135
+ last_response.headers['Set-Cookie'].should.match(/racket.session=/)
142
136
  response = JSON.parse(last_response.body)
143
137
  response.class.should.equal(Hash)
144
138
  response.keys.length.should.equal(2)
@@ -146,7 +140,7 @@ describe 'A default Racket test Application' do
146
140
  response.keys.should.include('session_id')
147
141
  get '/session_as_json?baz=quux'
148
142
  last_response.headers.keys.should.include('Set-Cookie')
149
- last_response.headers['Set-Cookie'].should.match(%r(racket.session=))
143
+ last_response.headers['Set-Cookie'].should.match(/racket.session=/)
150
144
  response = JSON.parse(last_response.body)
151
145
  response.class.should.equal(Hash)
152
146
  response.keys.length.should.equal(3)
@@ -155,14 +149,14 @@ describe 'A default Racket test Application' do
155
149
  response.keys.should.include('session_id')
156
150
  get '/session_as_json?drop_session'
157
151
  last_response.headers.keys.should.include('Set-Cookie')
158
- last_response.headers['Set-Cookie'].should.match(%r(racket.session=))
152
+ last_response.headers['Set-Cookie'].should.match(/racket.session=/)
159
153
  response = JSON.parse(last_response.body)
160
154
  response.class.should.equal(Hash)
161
155
  response.keys.should.be.empty
162
156
  get '/session_strings'
163
157
  response = JSON.parse(last_response.body)
164
158
  response.length.should.equal(3)
165
- response.each { |elem| elem.should.match(%r(Racket::Session)) }
159
+ response.each { |elem| elem.should.match(/Racket::Session/) }
166
160
  end
167
161
 
168
162
  it 'should be able to build paths correctly' do
@@ -173,7 +167,7 @@ describe 'A default Racket test Application' do
173
167
  end
174
168
 
175
169
  it 'should handle GET parameters correctly' do
176
- get '/sub2/get_some_data/?data1=foo&data3=bar'
170
+ get '/sub2/some_get_data/?data1=foo&data3=bar'
177
171
  last_response.status.should.equal(200)
178
172
  response = JSON.parse(last_response.body, symbolize_names: true)
179
173
  response.class.should.equal(Hash)
@@ -184,7 +178,7 @@ describe 'A default Racket test Application' do
184
178
  end
185
179
 
186
180
  it 'should handle POST parameters correctly' do
187
- post '/sub2/post_some_data', { data1: 'foo', data3: 'bar' }
181
+ post '/sub2/some_post_data', data1: 'foo', data3: 'bar'
188
182
  last_response.status.should.equal(200)
189
183
  response = JSON.parse(last_response.body, symbolize_names: true)
190
184
  response.class.should.equal(Hash)
@@ -207,5 +201,4 @@ describe 'A default Racket test Application' do
207
201
  last_response.headers['Content-Type'].should.equal('text/plain')
208
202
  last_response.body.should.equal('500 Internal Server Error')
209
203
  end
210
-
211
204
  end
data/spec/_invalid.rb CHANGED
@@ -6,9 +6,8 @@ describe 'An invalid Racket test Application' do
6
6
  end
7
7
 
8
8
  it 'should never initialize' do
9
- lambda { get '/' }
9
+ -> { get '/' }
10
10
  .should.raise(RuntimeError)
11
11
  .message.should.equal('Application has already been initialized!')
12
12
  end
13
-
14
13
  end
data/spec/_request.rb CHANGED
@@ -1,5 +1,4 @@
1
1
  describe 'Racket::Request should override Rack::Request correctly' do
2
-
3
2
  r = Racket::Request.new({}).freeze
4
3
 
5
4
  describe 'Racket::Request should inherit some methods from Rack::Request' do
@@ -45,5 +44,4 @@ describe 'Racket::Request should override Rack::Request correctly' do
45
44
  end
46
45
  end
47
46
  end
48
-
49
47
  end
data/spec/racket.rb CHANGED
@@ -11,8 +11,9 @@ if ENV['CI'] == 'true'
11
11
  SimpleCov.formatter = SimpleCov::Formatter::Codecov
12
12
  end
13
13
 
14
- TEST_DEFAULT_APP_DIR = File.absolute_path(File.join(File.dirname(__FILE__), 'test_default_app'))
15
- TEST_CUSTOM_APP_DIR = File.absolute_path(File.join(File.dirname(__FILE__), 'test_custom_app'))
14
+ TEST_DIR = File.absolute_path(File.dirname(__FILE__))
15
+ TEST_DEFAULT_APP_DIR = File.join(TEST_DIR, 'test_default_app')
16
+ TEST_CUSTOM_APP_DIR = File.join(TEST_DIR, 'test_custom_app')
16
17
 
17
18
  require 'racket'
18
19
 
@@ -22,9 +23,9 @@ require 'racket/helpers/file.rb'
22
23
  require 'rack/test'
23
24
  require 'bacon'
24
25
 
25
- require_relative '_request.rb'
26
+ require File.join(TEST_DIR, '_request.rb')
26
27
 
27
- Dir.chdir(TEST_DEFAULT_APP_DIR) { require_relative '_default.rb' }
28
- Dir.chdir(TEST_CUSTOM_APP_DIR) { require_relative '_custom.rb' }
28
+ Dir.chdir(TEST_DEFAULT_APP_DIR) { require File.join(TEST_DIR, '_default.rb') }
29
+ Dir.chdir(TEST_CUSTOM_APP_DIR) { require File.join(TEST_DIR, '_custom.rb') }
29
30
 
30
- require_relative '_invalid.rb'
31
+ require File.join(TEST_DIR, '_invalid.rb')
@@ -1,5 +1,5 @@
1
+ # Custom sub controller 1
1
2
  class CustomSubController1 < Racket::Controller
2
-
3
3
  helper :file
4
4
 
5
5
  def index
@@ -37,5 +37,4 @@ class CustomSubController1 < Racket::Controller
37
37
  def send_nonexisting_file
38
38
  send_file('files/no_such_thing.jpg')
39
39
  end
40
-
41
40
  end
@@ -1,5 +1,5 @@
1
+ # Custom sub controller 2
1
2
  class CustomSubController2 < Racket::Controller
2
-
3
3
  def index
4
4
  "#{self.class}::#{__method__}"
5
5
  end
@@ -30,5 +30,4 @@ class CustomSubController2 < Racket::Controller
30
30
  end
31
31
 
32
32
  helper :nonexisting
33
-
34
33
  end
@@ -1,5 +1,5 @@
1
+ # Custom sub controller 3
1
2
  class CustomSubController3 < Racket::Controller
2
-
3
3
  set_option(:top_secret, 42)
4
4
 
5
5
  def index
@@ -23,5 +23,4 @@ class CustomSubController3 < Racket::Controller
23
23
  obj.instance_eval { @secret = 42 }
24
24
  render_template('files/secret.erb', obj)
25
25
  end
26
-
27
26
  end
@@ -1,9 +1,8 @@
1
1
  require_relative '../custom_sub_controller_3.rb'
2
2
 
3
+ # Custom inherited controller
3
4
  class CustomInheritedController < CustomSubController3
4
-
5
5
  def index
6
6
  "#{self.class}::#{__method__}"
7
7
  end
8
-
9
8
  end
@@ -0,0 +1,25 @@
1
+ # Custom sub controller 4
2
+ class CustomSubController4 < Racket::Controller
3
+ set_option :default_layout, -> { '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
+ end
@@ -1,7 +1,7 @@
1
1
  require 'json'
2
2
 
3
+ # Default root controller
3
4
  class DefaultRootController < Racket::Controller
4
-
5
5
  def index
6
6
  "#{self.class}::#{__method__}"
7
7
  end
@@ -28,5 +28,4 @@ class DefaultRootController < Racket::Controller
28
28
  def session_strings
29
29
  [session.inspect, session.to_s, session.to_str].to_json
30
30
  end
31
-
32
31
  end
@@ -1,5 +1,5 @@
1
+ # Default sub controller 1
1
2
  class DefaultSubController1 < Racket::Controller
2
-
3
3
  def index
4
4
  "#{self.class}::#{__method__}"
5
5
  end
@@ -15,5 +15,4 @@ class DefaultSubController1 < Racket::Controller
15
15
  def epic_fail
16
16
  fail 'Epic fail!'
17
17
  end
18
-
19
18
  end
@@ -1,5 +1,5 @@
1
+ # Default sub controller 2
1
2
  class DefaultSubController2 < Racket::Controller
2
-
3
3
  def index
4
4
  "#{self.class}::#{__method__}"
5
5
  end
@@ -12,7 +12,7 @@ class DefaultSubController2 < Racket::Controller
12
12
  racket.params.to_json
13
13
  end
14
14
 
15
- def get_some_data
15
+ def some_get_data
16
16
  data = {}
17
17
  [:data1, :data2, :data3].each do |d|
18
18
  data[d] = request.get(d)
@@ -20,12 +20,11 @@ class DefaultSubController2 < Racket::Controller
20
20
  data.to_json
21
21
  end
22
22
 
23
- def post_some_data
23
+ def some_post_data
24
24
  data = {}
25
25
  [:data1, :data2, :data3].each do |d|
26
26
  data[d] = request.post(d)
27
27
  end
28
28
  data.to_json
29
29
  end
30
-
31
30
  end
@@ -1,7 +1,18 @@
1
+ # Default sub controller 3
1
2
  class DefaultSubController3 < Racket::Controller
2
-
3
3
  def index
4
4
  "#{self.class}::#{__method__}"
5
5
  end
6
6
 
7
+ protected
8
+
9
+ def protected_method
10
+ "I'm protected"
11
+ end
12
+
13
+ private
14
+
15
+ def private_method
16
+ "I'm private"
17
+ end
7
18
  end
@@ -1,9 +1,8 @@
1
1
  require_relative '../default_sub_controller_3.rb'
2
2
 
3
+ # Default inherited controller
3
4
  class DefaultInheritedController < DefaultSubController3
4
-
5
5
  def index
6
6
  "#{self.class}::#{__method__}"
7
7
  end
8
-
9
8
  end
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.1
4
+ version: 0.2.2
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-24 00:00:00.000000000 Z
11
+ date: 2015-09-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: http_router
@@ -159,6 +159,7 @@ files:
159
159
  - lib/racket/utils.rb
160
160
  - lib/racket/version.rb
161
161
  - lib/racket/view_manager.rb
162
+ - rake/utils.rb
162
163
  - spec/_custom.rb
163
164
  - spec/_default.rb
164
165
  - spec/_invalid.rb
@@ -168,7 +169,7 @@ files:
168
169
  - spec/test_custom_app/controllers/sub2/custom_sub_controller_2.rb
169
170
  - spec/test_custom_app/controllers/sub3/custom_sub_controller_3.rb
170
171
  - spec/test_custom_app/controllers/sub3/inherited/custom_inherited_controller.rb
171
- - spec/test_custom_app/controllers/sub4/default_sub_controller_4.rb
172
+ - spec/test_custom_app/controllers/sub4/custom_sub_controller_4.rb
172
173
  - spec/test_custom_app/extra/blob.rb
173
174
  - spec/test_custom_app/extra/blob/inner_blob.rb
174
175
  - spec/test_custom_app/files/plain_text.txt
@@ -1,26 +0,0 @@
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