racket-mvc 0.1.1 → 0.2.0

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