lotus-controller 0.3.2 → 0.4.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: 6ca9d4aeba96621f489499f6dc67a58b62b5dd66
4
- data.tar.gz: f86c1e2d695ac2fb3bc595a6fb6b587edd4f6bc1
3
+ metadata.gz: 69d59a1b6b0f96e6af7bf468a3003a45992b17a3
4
+ data.tar.gz: 93d926cb9fdf962ef3e55d6c5c1efb6de4b546ad
5
5
  SHA512:
6
- metadata.gz: 5597d8bc2fe5a15577a6698577adb1f9895c5c37353faed252b045974010b351994cfadcadf3d49215a76b5477aab5d95487d84e570b8913a8a0669ae0dee473
7
- data.tar.gz: a8e9f5b71b887a6db599e93e7eb555bb1fa556d33ac0ae5f9c095c18f2b55b29bdf53822b9fa459615c03cedf965d564ef4ee52e347d56bc412aaa1e3ff98133
6
+ metadata.gz: 129a9981a8f46af6d2cd149b9c811a81011cbc3e68b92af5e428e9d9cdc5afc1bb6070b605900acf231a4612d0eaf2c23088c7c17097c1c83aec9c030d5daa27
7
+ data.tar.gz: 35da235765f394db0fbcbbe3770732ee3e308825981f9634c0f6e6a626e72acbd3188c00939dfcce097a689e706f1de8ea90814cc435bc30be4d74ac7511f765
data/CHANGELOG.md CHANGED
@@ -1,6 +1,16 @@
1
1
  # Lotus::Controller
2
2
  Complete, fast and testable actions for Rack
3
3
 
4
+ ## v0.4.0 - 2015-03-23
5
+ ### Added
6
+ - [Erol Fornoles] `Action.use` now accepts a block
7
+ - [Alfonso Uceda Pompa] Introduced `Lotus::Controller::Configuration#cookies` as default cookie options.
8
+ - [Alfonso Uceda Pompa] Introduced `Lotus::Controller::Configuration#default_headers` as default HTTP headers to return in all the responses.
9
+ - [Luca Guidi] Introduced `Lotus::Action::Params#get` as a safe API to access nested params.
10
+
11
+ ### Changed
12
+ - [Alfonso Uceda Pompa] `redirect_to` now is a flow control method: it terminates the execution of an action, including the callbacks.
13
+
4
14
  ## v0.3.2 - 2015-01-30
5
15
  ### Added
6
16
  - [Alfonso Uceda Pompa] Callbacks: introduced `append_before` (alias of `before`), `append_after` (alias of `after`), `prepend_before` and `prepend_after`.
@@ -68,7 +68,7 @@ module Lotus
68
68
  def call(env)
69
69
  _rescue do
70
70
  @_env = env
71
- @headers = ::Rack::Utils::HeaderHash.new
71
+ @headers = ::Rack::Utils::HeaderHash.new(configuration.default_headers)
72
72
  @params = self.class.params_class.new(@_env)
73
73
  super @params
74
74
  end
@@ -36,9 +36,10 @@ module Lotus
36
36
  # @return [CookieJar]
37
37
  #
38
38
  # @since 0.1.0
39
- def initialize(env, headers)
40
- @_headers = headers
41
- @cookies = Utils::Hash.new(extract(env)).symbolize!
39
+ def initialize(env, headers, default_options)
40
+ @_headers = headers
41
+ @cookies = Utils::Hash.new(extract(env)).symbolize!
42
+ @default_options = default_options
42
43
  end
43
44
 
44
45
  # Finalize itself, by setting the proper headers to add and remove
@@ -50,7 +51,7 @@ module Lotus
50
51
  #
51
52
  # @see Lotus::Action::Cookies#finish
52
53
  def finish
53
- @cookies.each {|k,v| v.nil? ? delete_cookie(k) : set_cookie(k, v) }
54
+ @cookies.each { |k,v| v.nil? ? delete_cookie(k) : set_cookie(k, _merge_default_values(v)) }
54
55
  end
55
56
 
56
57
  # Returns the object associated with the given key
@@ -77,6 +78,21 @@ module Lotus
77
78
  end
78
79
 
79
80
  private
81
+
82
+ # Merge default cookies options with values provided by user
83
+ #
84
+ # Cookies values provided by user are respected
85
+ #
86
+ # @since 0.4.0
87
+ # @api private
88
+ def _merge_default_values(value)
89
+ cookies_options = if value.is_a? Hash
90
+ value
91
+ else
92
+ { value: value }
93
+ end
94
+ @default_options.merge cookies_options
95
+ end
80
96
  # Extract the cookies from the raw Rack env.
81
97
  #
82
98
  # This implementation is borrowed from Rack::Request#cookies.
@@ -41,7 +41,7 @@ module Lotus
41
41
  # end
42
42
  # end
43
43
  def cookies
44
- @cookies ||= CookieJar.new(@_env.dup, headers)
44
+ @cookies ||= CookieJar.new(@_env.dup, headers, configuration.cookies)
45
45
  end
46
46
 
47
47
  private
@@ -12,6 +12,12 @@ module Lotus
12
12
  # @api private
13
13
  SESSION_KEY = :__flash
14
14
 
15
+ # Session key where the last request_id is stored
16
+ #
17
+ # @since 0.4.0
18
+ # @api private
19
+ LAST_REQUEST_KEY = :__last_request_id
20
+
15
21
  # Initialize a new Flash instance
16
22
  #
17
23
  # @param session [Rack::Session::Abstract::SessionHash] the session
@@ -22,8 +28,9 @@ module Lotus
22
28
  # @see http://www.rubydoc.info/gems/rack/Rack/Session/Abstract/SessionHash
23
29
  # @see Lotus::Action::Rack#session_id
24
30
  def initialize(session, request_id)
25
- @session = session
26
- @request_id = request_id
31
+ @session = session
32
+ @request_id = request_id
33
+ @last_request_id = session[LAST_REQUEST_KEY]
27
34
 
28
35
  session[SESSION_KEY] ||= {}
29
36
  session[SESSION_KEY][request_id] ||= {}
@@ -47,7 +54,7 @@ module Lotus
47
54
  # @since 0.3.0
48
55
  # @api private
49
56
  def [](key)
50
- data.fetch(key) do
57
+ last_request_flash.merge(data).fetch(key) do
51
58
  _values.find {|data| !data[key].nil? }
52
59
  end
53
60
  end
@@ -66,6 +73,7 @@ module Lotus
66
73
  # It may happen that `#flash` is nil, and those two methods will fail
67
74
  unless flash.nil?
68
75
  expire_stale!
76
+ set_last_request_id!
69
77
  remove!
70
78
  end
71
79
  end
@@ -111,7 +119,7 @@ module Lotus
111
119
  # @api private
112
120
  def expire_stale!
113
121
  flash.each do |request_id, _|
114
- flash.delete(request_id) if @request_id != request_id
122
+ flash.delete(request_id) if delete?(request_id)
115
123
  end
116
124
  end
117
125
 
@@ -136,6 +144,39 @@ module Lotus
136
144
  def _values
137
145
  flash.values
138
146
  end
147
+
148
+ # Determine if delete data from flash for the given Request ID
149
+ #
150
+ # @return [TrueClass,FalseClass] the result of the check
151
+ #
152
+ # @since 0.4.0
153
+ # @api private
154
+ #
155
+ # @see Lotus::Action::Flash#expire_stale!
156
+ def delete?(request_id)
157
+ ![@request_id, @session[LAST_REQUEST_KEY]].include?(request_id)
158
+ end
159
+
160
+ # Get the last request session flash
161
+ #
162
+ # @return [Hash] the flash of last request
163
+ #
164
+ # @since 0.4.0
165
+ # @api private
166
+ def last_request_flash
167
+ flash[@last_request_id] || {}
168
+ end
169
+
170
+ # Store the last request_id to create the next flash with its values
171
+ # is current flash is not empty.
172
+ #
173
+ # @return [void]
174
+ # @since 0.4.0
175
+ # @api private
176
+ def set_last_request_id!
177
+ @session[LAST_REQUEST_KEY] = @request_id if !empty?
178
+ end
179
+
139
180
  end
140
181
  end
141
182
  end
@@ -14,6 +14,32 @@ module Lotus
14
14
  # @api private
15
15
  HTTP_STATUSES_WITHOUT_BODY = Set.new((100..199).to_a << 204 << 205 << 304).freeze
16
16
 
17
+
18
+ # Entity headers allowed in blank body responses, according to
19
+ # RFC 2616 - Section 10 (HTTP 1.1).
20
+ #
21
+ # "The response MAY include new or updated metainformation in the form
22
+ # of entity-headers".
23
+ #
24
+ # @since 0.4.0
25
+ # @api private
26
+ #
27
+ # @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.5
28
+ # @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec7.html
29
+ ENTITY_HEADERS = {
30
+ 'Allow' => true,
31
+ 'Content-Encoding' => true,
32
+ 'Content-Language' => true,
33
+ 'Content-Length' => true,
34
+ 'Content-Location' => true,
35
+ 'Content-MD5' => true,
36
+ 'Content-Range' => true,
37
+ 'Content-Type' => true,
38
+ 'Expires' => true,
39
+ 'Last-Modified' => true,
40
+ 'extension-header' => true
41
+ }.freeze
42
+
17
43
  # Ensures to not send body or headers for HEAD requests and/or for status
18
44
  # codes that doesn't allow them.
19
45
  #
@@ -26,6 +52,7 @@ module Lotus
26
52
 
27
53
  if _requires_no_body?
28
54
  @_body = nil
55
+ @headers.reject! { |header,_| !ENTITY_HEADERS.include?(header) }
29
56
  end
30
57
  end
31
58
 
@@ -26,6 +26,14 @@ module Lotus
26
26
  # @since 0.1.0
27
27
  ROUTER_PARAMS = 'router.params'.freeze
28
28
 
29
+ # Separator for #get
30
+ #
31
+ # @since 0.4.0
32
+ # @api private
33
+ #
34
+ # @see Lotus::Action::Params#get
35
+ GET_SEPARATOR = '.'.freeze
36
+
29
37
  # Whitelist and validate a parameter
30
38
  #
31
39
  # @param name [#to_sym] The name of the param to whitelist
@@ -137,6 +145,52 @@ module Lotus
137
145
  @attributes.get(key)
138
146
  end
139
147
 
148
+ # Get an attribute value associated with the given key.
149
+ # Nested attributes are reached with a dot notation.
150
+ #
151
+ # @param key [String] the key
152
+ #
153
+ # @return [Object,NilClass] return the associated value, if found
154
+ #
155
+ # @since 0.4.0
156
+ #
157
+ # @example
158
+ # require 'lotus/controller'
159
+ #
160
+ # module Deliveries
161
+ # class Create
162
+ # include Lotus::Action
163
+ #
164
+ # params do
165
+ # param :customer_name
166
+ # param :address do
167
+ # param :city
168
+ # end
169
+ # end
170
+ #
171
+ # def call(params)
172
+ # params.get('customer_name') # => "Luca"
173
+ # params.get('uknown') # => nil
174
+ #
175
+ # params.get('address.city') # => "Rome"
176
+ # params.get('address.unknown') # => nil
177
+ #
178
+ # params.get(nil) # => nil
179
+ # end
180
+ # end
181
+ # end
182
+ def get(key)
183
+ key, *keys = key.to_s.split(GET_SEPARATOR)
184
+ result = self[key]
185
+
186
+ Array(keys).each do |k|
187
+ break if result.nil?
188
+ result = result[k]
189
+ end
190
+
191
+ result
192
+ end
193
+
140
194
  # Returns the Ruby's hash
141
195
  #
142
196
  # @return [Hash]
@@ -94,8 +94,8 @@ module Lotus
94
94
  # end
95
95
  # end
96
96
  # end
97
- def use(middleware, *args)
98
- rack_builder.use middleware, *args
97
+ def use(middleware, *args, &block)
98
+ rack_builder.use middleware, *args, &block
99
99
  end
100
100
  end
101
101
 
@@ -9,7 +9,7 @@ module Lotus
9
9
  # @param env [Hash] the full Rack env or the params. This value may vary,
10
10
  # see the examples below.
11
11
  #
12
- # @since x.x.x
12
+ # @since 0.4.0
13
13
  #
14
14
  # @see Lotus::Action::Rack::ClassMethods#rack_builder
15
15
  # @see Lotus::Action::Rack::ClassMethods#use
@@ -21,7 +21,7 @@ module Lotus
21
21
  # def initialize(app)
22
22
  # @app = app
23
23
  # end
24
- #
24
+ #
25
25
  # def call(env)
26
26
  # #...
27
27
  # end
@@ -44,4 +44,4 @@ module Lotus
44
44
  end
45
45
  end
46
46
  end
47
- end
47
+ end
@@ -12,13 +12,15 @@ module Lotus
12
12
 
13
13
  private
14
14
 
15
- # Redirect to the given URL
15
+ # Redirect to the given URL and halt the request
16
16
  #
17
17
  # @param url [String] the destination URL
18
18
  # @param status [Fixnum] the http code
19
19
  #
20
20
  # @since 0.1.0
21
21
  #
22
+ # @see Lotus::Action::Throwable#halt
23
+ #
22
24
  # @example With default status code (302)
23
25
  # require 'lotus/controller'
24
26
  #
@@ -50,7 +52,7 @@ module Lotus
50
52
  # action.call({}) # => [301, {'Location' => '/articles/23'}, '']
51
53
  def redirect_to(url, status: 302)
52
54
  headers[LOCATION] = url
53
- self.status = status
55
+ halt(status)
54
56
  end
55
57
  end
56
58
  end
@@ -112,8 +112,8 @@ module Lotus
112
112
  # # The validation errors caused by Comments::Create are available
113
113
  # # **after the redirect** in the context of Comments::Index.
114
114
  def redirect_to(*args)
115
- super
116
115
  flash[ERRORS_KEY] = errors.to_a unless params.valid?
116
+ super
117
117
  end
118
118
 
119
119
  # Read errors from flash or delegate to the superclass
@@ -469,6 +469,67 @@ module Lotus
469
469
  end
470
470
  end
471
471
 
472
+ # Set default headers for all responses
473
+ #
474
+ # By default this value is an empty hash.
475
+ #
476
+ # @since 0.4.0
477
+ #
478
+ # @example Getting the value
479
+ # require 'lotus/controller'
480
+ #
481
+ # Lotus::Controller.configuration.default_headers # => {}
482
+ #
483
+ # @example Setting the value
484
+ # require 'lotus/controller'
485
+ #
486
+ # Lotus::Controller.configure do
487
+ # default_headers({
488
+ # 'X-Frame-Options' => 'DENY'
489
+ # })
490
+ # end
491
+ def default_headers(headers = nil)
492
+ if headers
493
+ @default_headers.merge!(
494
+ headers.reject {|_,v| v.nil? }
495
+ )
496
+ else
497
+ @default_headers
498
+ end
499
+ end
500
+
501
+ # Set default cookies options for all responses
502
+ #
503
+ # By default this value is an empty hash.
504
+ #
505
+ # @since 0.4.0
506
+ #
507
+ # @example Getting the value
508
+ # require 'lotus/controller'
509
+ #
510
+ # Lotus::Controller.configuration.cookies # => {}
511
+ #
512
+ # @example Setting the value
513
+ # require 'lotus/controller'
514
+ #
515
+ # Lotus::Controller.configure do
516
+ # cookies({
517
+ # domain: 'lotusrb.org',
518
+ # path: '/controller',
519
+ # secure: true,
520
+ # httponly: true
521
+ # })
522
+ # end
523
+ def cookies(options = nil)
524
+ if options
525
+ @cookies.merge!(
526
+ options.reject { |_, v| v.nil? }
527
+ )
528
+ else
529
+ @cookies
530
+ end
531
+ end
532
+
472
533
  # Returns a format for the given mime type
473
534
  #
474
535
  # @param mime_type [#to_s,#to_str] A mime type
@@ -503,13 +564,15 @@ module Lotus
503
564
  # @api private
504
565
  def duplicate
505
566
  Configuration.new.tap do |c|
506
- c.handle_exceptions = handle_exceptions
507
- c.handled_exceptions = handled_exceptions.dup
508
- c.action_module = action_module
509
- c.modules = modules.dup
510
- c.formats = formats.dup
511
- c.default_format = default_format
512
- c.default_charset = default_charset
567
+ c.handle_exceptions = handle_exceptions
568
+ c.handled_exceptions = handled_exceptions.dup
569
+ c.action_module = action_module
570
+ c.modules = modules.dup
571
+ c.formats = formats.dup
572
+ c.default_format = default_format
573
+ c.default_charset = default_charset
574
+ c.default_headers = default_headers.dup
575
+ c.cookies = cookies.dup
513
576
  end
514
577
  end
515
578
 
@@ -534,6 +597,8 @@ module Lotus
534
597
  @formats = DEFAULT_FORMATS.dup
535
598
  @default_format = nil
536
599
  @default_charset = nil
600
+ @default_headers = {}
601
+ @cookies = {}
537
602
  @action_module = ::Lotus::Action
538
603
  end
539
604
 
@@ -569,6 +634,8 @@ module Lotus
569
634
  attr_writer :modules
570
635
  attr_writer :default_format
571
636
  attr_writer :default_charset
637
+ attr_writer :default_headers
638
+ attr_writer :cookies
572
639
  end
573
640
  end
574
641
  end
@@ -3,6 +3,6 @@ module Lotus
3
3
  # Defines the version
4
4
  #
5
5
  # @since 0.1.0
6
- VERSION = '0.3.2'.freeze
6
+ VERSION = '0.4.0'.freeze
7
7
  end
8
8
  end
@@ -20,8 +20,8 @@ Gem::Specification.new do |spec|
20
20
  spec.required_ruby_version = '>= 2.0.0'
21
21
 
22
22
  spec.add_dependency 'rack', '~> 1.5'
23
- spec.add_dependency 'lotus-utils', '~> 0.3', '>= 0.3.4'
24
- spec.add_dependency 'lotus-validations', '~> 0.2', '>= 0.2.4'
23
+ spec.add_dependency 'lotus-utils', '~> 0.4'
24
+ spec.add_dependency 'lotus-validations', '~> 0.3'
25
25
 
26
26
  spec.add_development_dependency 'bundler', '~> 1.6'
27
27
  spec.add_development_dependency 'minitest', '~> 5'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lotus-controller
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.2
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Luca Guidi
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2015-01-30 00:00:00.000000000 Z
12
+ date: 2015-03-23 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rack
@@ -31,40 +31,28 @@ dependencies:
31
31
  requirements:
32
32
  - - "~>"
33
33
  - !ruby/object:Gem::Version
34
- version: '0.3'
35
- - - ">="
36
- - !ruby/object:Gem::Version
37
- version: 0.3.4
34
+ version: '0.4'
38
35
  type: :runtime
39
36
  prerelease: false
40
37
  version_requirements: !ruby/object:Gem::Requirement
41
38
  requirements:
42
39
  - - "~>"
43
40
  - !ruby/object:Gem::Version
44
- version: '0.3'
45
- - - ">="
46
- - !ruby/object:Gem::Version
47
- version: 0.3.4
41
+ version: '0.4'
48
42
  - !ruby/object:Gem::Dependency
49
43
  name: lotus-validations
50
44
  requirement: !ruby/object:Gem::Requirement
51
45
  requirements:
52
46
  - - "~>"
53
47
  - !ruby/object:Gem::Version
54
- version: '0.2'
55
- - - ">="
56
- - !ruby/object:Gem::Version
57
- version: 0.2.4
48
+ version: '0.3'
58
49
  type: :runtime
59
50
  prerelease: false
60
51
  version_requirements: !ruby/object:Gem::Requirement
61
52
  requirements:
62
53
  - - "~>"
63
54
  - !ruby/object:Gem::Version
64
- version: '0.2'
65
- - - ">="
66
- - !ruby/object:Gem::Version
67
- version: 0.2.4
55
+ version: '0.3'
68
56
  - !ruby/object:Gem::Dependency
69
57
  name: bundler
70
58
  requirement: !ruby/object:Gem::Requirement
@@ -183,7 +171,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
183
171
  version: '0'
184
172
  requirements: []
185
173
  rubyforge_project:
186
- rubygems_version: 2.2.2
174
+ rubygems_version: 2.4.5
187
175
  signing_key:
188
176
  specification_version: 4
189
177
  summary: Complete, fast and testable actions for Rack and Lotus