racket-mvc 0.1.1 → 0.2.0

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: aa507274155a8638944da1b19957b0423499a3aa
4
- data.tar.gz: 54631b41e9a2ec392b7bb41fd23a87c93ea1df02
3
+ metadata.gz: d06a12ceb8db8f9e2cafd0d649048e03da1e7644
4
+ data.tar.gz: 7534148f29e1c2c00b65800c4b1fa41ea3705a08
5
5
  SHA512:
6
- metadata.gz: e1e402abcbadc38764b851c7b014e39493692b71247f0db412d75d063b5c844c9048c2faa2dc695f37cb53ee9809d8386a2cae994d0b76afa10952f0889af03e
7
- data.tar.gz: 65c154fb5ecdb60e364500614f7f7eb1346d3054a1923ec092a0cf52c874a16b150cd383d2aca07cd0ad9dd8455a4500bdde53a24e26b87601f80f946d8bfe29
6
+ metadata.gz: a929335cdea51bbabbc0f0531de67cacf63177ec042f33dfd373454c2284e06603da7ee50b188584d76db7de02572bb99de0cbfdeb57259e903b2feb4d4470c0
7
+ data.tar.gz: bb0f3f128237c989d4937d612d5c0b6dc9d248f72e7233fc5900672526d9c72760816ba2fa53ed50c784bcb1dbf2e602b00237e9bca07a7a06d0e89afe2cbb18
data/README.md CHANGED
@@ -29,7 +29,8 @@ Have a look in the `spec` directory. The code base have tests covering 100 per c
29
29
  - ruby 2.0
30
30
  - ruby 2.1.6
31
31
  - ruby 2.2.2
32
- - jruby (latest version, 1.9 mode only)
32
+ - jruby 1.7 (1.9 mode only)
33
+ - jruby 9.0.0.0
33
34
  - rbx-2 (latest version)
34
35
 
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.
@@ -100,7 +100,7 @@ module Racket
100
100
  # @param [Symbol] action
101
101
  # @param [Array] params
102
102
  # @return [String]
103
- def self.get_route(controller, action, params)
103
+ def self.get_route(controller, action = nil, *params)
104
104
  @router.get_route(controller, action, params)
105
105
  end
106
106
 
@@ -0,0 +1,55 @@
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
+ module Racket
20
+ # Helpers module
21
+ module Helpers
22
+ # Helper module that handles files
23
+ module File
24
+ # Sends the contents of a file to the client.
25
+ #
26
+ # @param [String] file
27
+ # @param [Hash] options
28
+ # @return [Array]
29
+ def send_file(file, options = {})
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)
37
+ headers = {}
38
+ mime_type = options.fetch(:mime_type, nil)
39
+ # Calculate MIME type if it was not already specified.
40
+ mime_type = Rack::Mime.mime_type(::File.extname(file)) unless mime_type
41
+ headers['Content-Type'] = mime_type
42
+ # Set Content-Disposition (and a file name) if the file should be downloaded
43
+ # 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
50
+ # Send response
51
+ respond!(200, headers, ::File.read(file))
52
+ end
53
+ end
54
+ end
55
+ end
@@ -27,7 +27,7 @@ module Racket
27
27
  # @param [Symbol] action
28
28
  # @param [Array] params
29
29
  # @return [String]
30
- def route(controller, action, *params)
30
+ def route(controller, action = nil, *params)
31
31
  Application.get_route(controller, action, params)
32
32
  end
33
33
 
@@ -38,7 +38,7 @@ module Racket
38
38
  # @param [Symbol] action
39
39
  # @param [Array] params
40
40
  # @return [String]
41
- def route_self(action, *params)
41
+ def route_self(action = nil, *params)
42
42
  Application.get_route(self.class, action, params)
43
43
  end
44
44
 
@@ -17,14 +17,39 @@
17
17
  # along with Racket. If not, see <http://www.gnu.org/licenses/>.
18
18
 
19
19
  module Racket
20
- # Represents an incoming request. Mostly matches Rack::Request but removes some methods that
21
- # don't fit with racket.
20
+ # Represents an incoming request. Mostly matches Rack::Request but removes/redefines
21
+ # methods relating to GET/POST parameters and sessions.
22
22
  class Request < Rack::Request
23
- # Force explicit use of request.GET and request.POST
24
- # For racket params, use racket.params
25
- undef_method :params
23
+ # Remove methods that use merged GET and POST data.
24
+ undef_method :[], :[]=, :delete_param, :params, :update_param, :values_at
26
25
 
27
- # Unless sessions are loaded explicitly, session methods should not be available
26
+ # Remove session methods.
28
27
  undef_method :session, :session_options
28
+
29
+ # Redefine methods for handling GET parameters
30
+ alias_method(:get_params, :GET)
31
+ undef_method :GET
32
+
33
+ # Returns a value from the GET parameter hash.
34
+ #
35
+ # @param [Object] key
36
+ # @param [Object] default
37
+ # @return [Object]
38
+ def get(key, default = nil)
39
+ get_params.fetch(key.to_s, default)
40
+ end
41
+
42
+ # Redefine methods for handling POST parameters
43
+ alias_method(:post_params, :POST)
44
+ undef_method :POST
45
+
46
+ # Returns a value from the POST parameter hash.
47
+ #
48
+ # @param [Object] key
49
+ # @param [Object] default
50
+ # @return [Object]
51
+ def post(key, default = nil)
52
+ post_params.fetch(key.to_s, default)
53
+ end
29
54
  end
30
55
  end
data/lib/racket/router.rb CHANGED
@@ -51,10 +51,11 @@ module Racket
51
51
  # @param [Array] params
52
52
  # @return [String]
53
53
  def get_route(controller, action, params)
54
+ fail "Cannot find controller #{controller}" unless @routes_by_controller.key?(controller)
55
+ params.flatten!
54
56
  route = ''
55
- route << @routes_by_controller[controller] if @routes_by_controller.key?(controller)
56
- action = action.to_s
57
- route << "/#{action}" unless action.empty?
57
+ route << @routes_by_controller[controller]
58
+ route << "/#{action}" unless action.nil?
58
59
  route << "/#{params.join('/')}" unless params.empty?
59
60
  route = route[1..-1] if route.start_with?('//') # Special case for root path
60
61
  route
@@ -23,10 +23,10 @@ module Racket
23
23
  # Major version
24
24
  MAJOR = 0
25
25
  # Minor version
26
- MINOR = 1
26
+ MINOR = 2
27
27
  # Teeny version
28
- TEENY = 1
29
- # Prerelease ?
28
+ TEENY = 0
29
+ # Is it a prerelease?
30
30
  PRERELEASE = false
31
31
 
32
32
  # Returns the current version of Racket as a string.
@@ -34,12 +34,14 @@ module Racket
34
34
  # @param [Controller] controller
35
35
  # @return [Hash]
36
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?('//')
37
39
  template =
38
- find_template(controller.request.path, controller.controller_option(:default_view))
40
+ find_template(template_path, controller.controller_option(:default_view))
39
41
  if template
40
42
  output = Tilt.new(template).render(controller)
41
43
  layout =
42
- find_layout(controller.request.path, controller.controller_option(:default_layout))
44
+ find_layout(template_path, controller.controller_option(:default_layout))
43
45
  output = Tilt.new(layout).render(controller) { output } if layout
44
46
  else
45
47
  output = controller.racket.action_result
data/spec/_custom.rb CHANGED
@@ -66,4 +66,44 @@ describe 'A custom Racket test Application' do
66
66
  last_response.headers['Content-Type'].should.equal('text/html')
67
67
  last_response.body.should.equal("The secret is 42!\n")
68
68
  end
69
+
70
+ it 'should be able to send files with auto mime type' do
71
+ get '/sub1/send_existing_file_auto_mime'
72
+ last_response.status.should.equal(200)
73
+ last_response.headers['Content-Type'].should.equal('text/plain')
74
+ last_response.headers.key?('Content-Disposition').should.equal(false)
75
+ last_response.body.should.equal("This is plain text.\n")
76
+ end
77
+
78
+ it 'should be able to send files with custom mime type' do
79
+ get '/sub1/send_existing_file_custom_mime'
80
+ last_response.status.should.equal(200)
81
+ last_response.headers['Content-Type'].should.equal('text/skv')
82
+ last_response.headers.key?('Content-Disposition').should.equal(false)
83
+ last_response.body.should.equal("This is plain text.\n")
84
+ end
85
+
86
+ it 'should be able to send unnamed files with Content-Disposition' do
87
+ get '/sub1/send_existing_file_unnamed_attachment'
88
+ last_response.status.should.equal(200)
89
+ last_response.headers['Content-Type'].should.equal('text/plain')
90
+ last_response.headers['Content-Disposition'].should.equal('attachment')
91
+ last_response.body.should.equal("This is plain text.\n")
92
+ end
93
+
94
+ it 'should be able to send named files with Content-Disposition' do
95
+ get '/sub1/send_existing_file_named_attachment'
96
+ last_response.status.should.equal(200)
97
+ last_response.headers['Content-Type'].should.equal('text/plain')
98
+ last_response.headers['Content-Disposition'].should.equal('attachment; filename="bazinga!.txt"')
99
+ last_response.body.should.equal("This is plain text.\n")
100
+ end
101
+
102
+ it 'should respond with 404 when trying to send non-existing files' do
103
+ get '/sub1/send_nonexisting_file'
104
+ last_response.status.should.equal(404)
105
+ last_response.headers['Content-Type'].should.equal('text/plain')
106
+ last_response.headers.key?('Content-Disposition').should.equal(false)
107
+ last_response.body.should.equal("Not Found")
108
+ end
69
109
  end
data/spec/_default.rb CHANGED
@@ -31,7 +31,7 @@ describe 'A default Racket test Application' do
31
31
  actions_by_controller[DefaultSubController1].length.should.equal(4)
32
32
  actions_by_controller[DefaultSubController1].include?(:route_to_root).should.equal(true)
33
33
  actions_by_controller[DefaultSubController1].include?(:route_to_nonexisting).should.equal(true)
34
- actions_by_controller[DefaultSubController2].length.should.equal(3)
34
+ actions_by_controller[DefaultSubController2].length.should.equal(5)
35
35
  actions_by_controller[DefaultSubController2].include?(:index).should.equal(true)
36
36
  actions_by_controller[DefaultSubController2].include?(:current_action).should.equal(true)
37
37
  actions_by_controller[DefaultSubController2].include?(:current_params).should.equal(true)
@@ -172,6 +172,28 @@ describe 'A default Racket test Application' do
172
172
  )
173
173
  end
174
174
 
175
+ it 'should handle GET parameters correctly' do
176
+ get '/sub2/get_some_data/?data1=foo&data3=bar'
177
+ last_response.status.should.equal(200)
178
+ response = JSON.parse(last_response.body, symbolize_names: true)
179
+ response.class.should.equal(Hash)
180
+ response.keys.sort.should.equal([:data1, :data2, :data3])
181
+ response[:data1].should.equal('foo')
182
+ response[:data2].should.equal(nil)
183
+ response[:data3].should.equal('bar')
184
+ end
185
+
186
+ it 'should handle POST parameters correctly' do
187
+ post '/sub2/post_some_data', { data1: 'foo', data3: 'bar' }
188
+ last_response.status.should.equal(200)
189
+ response = JSON.parse(last_response.body, symbolize_names: true)
190
+ response.class.should.equal(Hash)
191
+ response.keys.sort.should.equal([:data1, :data2, :data3])
192
+ response[:data1].should.equal('foo')
193
+ response[:data2].should.equal(nil)
194
+ response[:data3].should.equal('bar')
195
+ end
196
+
175
197
  it 'should be able to serve static files' do
176
198
  get '/hello.txt'
177
199
  last_response.status.should.equal(200)
data/spec/_request.rb ADDED
@@ -0,0 +1,49 @@
1
+ describe 'Racket::Request should override Rack::Request correctly' do
2
+
3
+ r = Racket::Request.new({}).freeze
4
+
5
+ describe 'Racket::Request should inherit some methods from Rack::Request' do
6
+ [
7
+ :accept_encoding, :accept_language, :base_url, :body, :content_charset, :content_length,
8
+ :content_type, :cookies, :delete?, :env, :form_data?, :fullpath, :get?, :head?, :host,
9
+ :host_with_port, :ip, :link?, :logger, :media_type, :media_type_params, :options?,
10
+ :parseable_data?, :patch?, :path, :path_info, :path_info=, :port, :post?, :put?,
11
+ :query_string, :referer, :referrer, :request_method, :scheme, :script_name, :script_name=,
12
+ :ssl?, :trace?, :trusted_proxy?, :unlink?, :url, :user_agent, :xhr?
13
+ ].each do |meth|
14
+ it "should inherit #{meth} from Rack::Request" do
15
+ r.respond_to?(meth).should.equal(true)
16
+ end
17
+ end
18
+ end
19
+
20
+ describe 'Racket::Request should not inherit methods that use merged GET and POST data' do
21
+ [:[], :[]=, :delete_param, :params, :update_param, :values_at].each do |meth|
22
+ it "should not inherit #{meth} from Rack::Request" do
23
+ r.respond_to?(meth).should.equal(false)
24
+ end
25
+ end
26
+ end
27
+
28
+ describe 'Racket::Request should not inherit session methods' do
29
+ [:session, :session_options].each do |meth|
30
+ it "should not inherit #{meth} from Rack::Request" do
31
+ r.respond_to?(meth).should.equal(false)
32
+ end
33
+ end
34
+ end
35
+
36
+ describe 'Racket::Request should redefine methods for handling GET/POST data' do
37
+ [:get, :get_params, :post, :post_params].each do |meth|
38
+ it "should define #{meth}" do
39
+ r.respond_to?(meth).should.equal(true)
40
+ end
41
+ end
42
+ [:GET, :POST].each do |meth|
43
+ it "should not define #{meth}" do
44
+ r.respond_to?(meth).should.equal(false)
45
+ end
46
+ end
47
+ end
48
+
49
+ end
data/spec/racket.rb CHANGED
@@ -15,9 +15,15 @@ TEST_DEFAULT_APP_DIR = File.absolute_path(File.join(File.dirname(__FILE__), 'tes
15
15
  TEST_CUSTOM_APP_DIR = File.absolute_path(File.join(File.dirname(__FILE__), 'test_custom_app'))
16
16
 
17
17
  require 'racket'
18
+
19
+ # Make sure some files that are loaded dynamically get coverage as well.
20
+ require 'racket/helpers/file.rb'
21
+
18
22
  require 'rack/test'
19
23
  require 'bacon'
20
24
 
25
+ require_relative '_request.rb'
26
+
21
27
  Dir.chdir(TEST_DEFAULT_APP_DIR) { require_relative '_default.rb' }
22
28
  Dir.chdir(TEST_CUSTOM_APP_DIR) { require_relative '_custom.rb' }
23
29
 
@@ -1,5 +1,7 @@
1
1
  class CustomSubController1 < Racket::Controller
2
2
 
3
+ helper :file
4
+
3
5
  def index
4
6
  "#{self.class}::#{__method__}"
5
7
  end
@@ -11,9 +13,29 @@ class CustomSubController1 < Racket::Controller
11
13
  def route_to_nonexisting
12
14
  r(CustomInheritedController, :nonono, :with, :params)
13
15
  end
14
-
16
+
15
17
  def epic_fail
16
18
  fail 'Epic fail!'
17
19
  end
18
20
 
21
+ def send_existing_file_auto_mime
22
+ send_file('files/plain_text.txt')
23
+ end
24
+
25
+ def send_existing_file_custom_mime
26
+ send_file('files/plain_text.txt', mime_type: 'text/skv')
27
+ end
28
+
29
+ def send_existing_file_unnamed_attachment
30
+ send_file('files/plain_text.txt', download: true)
31
+ end
32
+
33
+ def send_existing_file_named_attachment
34
+ send_file('files/plain_text.txt', download: true, filename: 'bazinga!.txt')
35
+ end
36
+
37
+ def send_nonexisting_file
38
+ send_file('files/no_such_thing.jpg')
39
+ end
40
+
19
41
  end
@@ -0,0 +1 @@
1
+ This is plain text.
@@ -15,7 +15,7 @@ class DefaultRootController < Racket::Controller
15
15
  end
16
16
 
17
17
  def session_as_json
18
- request.GET.each_pair do |key, value|
18
+ request.get_params.each_pair do |key, value|
19
19
  if key == 'drop_session'
20
20
  session.clear
21
21
  else
@@ -12,4 +12,20 @@ class DefaultSubController2 < Racket::Controller
12
12
  racket.params.to_json
13
13
  end
14
14
 
15
+ def get_some_data
16
+ data = {}
17
+ [:data1, :data2, :data3].each do |d|
18
+ data[d] = request.get(d)
19
+ end
20
+ data.to_json
21
+ end
22
+
23
+ def post_some_data
24
+ data = {}
25
+ [:data1, :data2, :data3].each do |d|
26
+ data[d] = request.post(d)
27
+ end
28
+ data.to_json
29
+ end
30
+
15
31
  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.1.1
4
+ version: 0.2.0
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-07-26 00:00:00.000000000 Z
11
+ date: 2015-08-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: http_router
@@ -98,16 +98,16 @@ dependencies:
98
98
  name: rake
99
99
  requirement: !ruby/object:Gem::Requirement
100
100
  requirements:
101
- - - ">="
101
+ - - "~>"
102
102
  - !ruby/object:Gem::Version
103
- version: '0'
103
+ version: '10'
104
104
  type: :development
105
105
  prerelease: false
106
106
  version_requirements: !ruby/object:Gem::Requirement
107
107
  requirements:
108
- - - ">="
108
+ - - "~>"
109
109
  - !ruby/object:Gem::Version
110
- version: '0'
110
+ version: '10'
111
111
  - !ruby/object:Gem::Dependency
112
112
  name: simplecov
113
113
  requirement: !ruby/object:Gem::Requirement
@@ -126,14 +126,14 @@ dependencies:
126
126
  name: yard
127
127
  requirement: !ruby/object:Gem::Requirement
128
128
  requirements:
129
- - - ">="
129
+ - - "~>"
130
130
  - !ruby/object:Gem::Version
131
131
  version: '0'
132
132
  type: :development
133
133
  prerelease: false
134
134
  version_requirements: !ruby/object:Gem::Requirement
135
135
  requirements:
136
- - - ">="
136
+ - - "~>"
137
137
  - !ruby/object:Gem::Version
138
138
  version: '0'
139
139
  description: Racket is a small MVC framework built on top of rack.
@@ -149,6 +149,7 @@ files:
149
149
  - lib/racket/application.rb
150
150
  - lib/racket/controller.rb
151
151
  - lib/racket/current.rb
152
+ - lib/racket/helpers/file.rb
152
153
  - lib/racket/helpers/routing.rb
153
154
  - lib/racket/helpers/view.rb
154
155
  - lib/racket/request.rb
@@ -161,6 +162,7 @@ files:
161
162
  - spec/_custom.rb
162
163
  - spec/_default.rb
163
164
  - spec/_invalid.rb
165
+ - spec/_request.rb
164
166
  - spec/racket.rb
165
167
  - spec/test_custom_app/controllers/sub1/custom_sub_controller_1.rb
166
168
  - spec/test_custom_app/controllers/sub2/custom_sub_controller_2.rb
@@ -168,6 +170,7 @@ files:
168
170
  - spec/test_custom_app/controllers/sub3/inherited/custom_inherited_controller.rb
169
171
  - spec/test_custom_app/extra/blob.rb
170
172
  - spec/test_custom_app/extra/blob/inner_blob.rb
173
+ - spec/test_custom_app/files/plain_text.txt
171
174
  - spec/test_custom_app/files/secret.erb
172
175
  - spec/test_custom_app/layouts/sub2/zebra.erb
173
176
  - spec/test_custom_app/templates/sub2/template.erb