lotus-controller 0.2.0 → 0.3.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 +4 -4
- data/CHANGELOG.md +65 -127
- data/README.md +289 -89
- data/lib/lotus/action.rb +12 -6
- data/lib/lotus/action/cache.rb +174 -0
- data/lib/lotus/action/cache/cache_control.rb +70 -0
- data/lib/lotus/action/cache/conditional_get.rb +93 -0
- data/lib/lotus/action/cache/directives.rb +99 -0
- data/lib/lotus/action/cache/expires.rb +73 -0
- data/lib/lotus/action/callable.rb +3 -2
- data/lib/lotus/action/callbacks.rb +8 -0
- data/lib/lotus/action/configurable.rb +3 -2
- data/lib/lotus/action/cookies.rb +13 -12
- data/lib/lotus/action/exposable.rb +31 -4
- data/lib/lotus/action/flash.rb +141 -0
- data/lib/lotus/action/glue.rb +35 -0
- data/lib/lotus/action/mime.rb +82 -4
- data/lib/lotus/action/params.rb +87 -3
- data/lib/lotus/action/rack.rb +66 -51
- data/lib/lotus/action/redirect.rb +21 -3
- data/lib/lotus/action/session.rb +97 -0
- data/lib/lotus/action/throwable.rb +24 -4
- data/lib/lotus/action/validatable.rb +128 -0
- data/lib/lotus/controller.rb +11 -25
- data/lib/lotus/controller/configuration.rb +117 -66
- data/lib/lotus/controller/version.rb +1 -1
- data/lib/lotus/http/status.rb +5 -1
- data/lib/rack-patch.rb +8 -2
- data/lotus-controller.gemspec +6 -4
- metadata +54 -21
- data/lib/lotus/controller/dsl.rb +0 -56
@@ -19,8 +19,12 @@ module Lotus
|
|
19
19
|
base.extend ClassMethods
|
20
20
|
end
|
21
21
|
|
22
|
+
# Throw API class methods
|
23
|
+
#
|
24
|
+
# @since 0.1.0
|
25
|
+
# @api private
|
22
26
|
module ClassMethods
|
23
|
-
|
27
|
+
private
|
24
28
|
|
25
29
|
# Handle the given exception with an HTTP status code.
|
26
30
|
#
|
@@ -74,8 +78,8 @@ module Lotus
|
|
74
78
|
# @see Lotus::Controller#handled_exceptions
|
75
79
|
# @see Lotus::Action::Throwable#handle_exception
|
76
80
|
# @see Lotus::Http::Status:ALL
|
77
|
-
def halt(code)
|
78
|
-
status(*Http::Status.for_code(code))
|
81
|
+
def halt(code = nil)
|
82
|
+
status(*Http::Status.for_code(code)) if code
|
79
83
|
throw :halt
|
80
84
|
end
|
81
85
|
|
@@ -124,7 +128,23 @@ module Lotus
|
|
124
128
|
# @api private
|
125
129
|
def _handle_exception(exception)
|
126
130
|
raise unless configuration.handle_exceptions
|
127
|
-
|
131
|
+
|
132
|
+
instance_exec(
|
133
|
+
exception,
|
134
|
+
&_exception_handler(exception)
|
135
|
+
)
|
136
|
+
end
|
137
|
+
|
138
|
+
# @since 0.3.0
|
139
|
+
# @api private
|
140
|
+
def _exception_handler(exception)
|
141
|
+
handler = configuration.exception_handler(exception)
|
142
|
+
|
143
|
+
if respond_to?(handler.to_s, true)
|
144
|
+
method(handler)
|
145
|
+
else
|
146
|
+
->(ex) { halt handler }
|
147
|
+
end
|
128
148
|
end
|
129
149
|
end
|
130
150
|
end
|
@@ -0,0 +1,128 @@
|
|
1
|
+
module Lotus
|
2
|
+
module Action
|
3
|
+
module Validatable
|
4
|
+
# Defines the class name for anoymous params
|
5
|
+
#
|
6
|
+
# @api private
|
7
|
+
# @since 0.3.0
|
8
|
+
PARAMS_CLASS_NAME = 'Params'.freeze
|
9
|
+
|
10
|
+
def self.included(base)
|
11
|
+
base.class_eval do
|
12
|
+
extend ClassMethods
|
13
|
+
expose :params, :errors
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
# Validatable API class methods
|
18
|
+
#
|
19
|
+
# @since 0.1.0
|
20
|
+
# @api private
|
21
|
+
module ClassMethods
|
22
|
+
# Whitelist valid parameters to be passed to Lotus::Action#call.
|
23
|
+
#
|
24
|
+
# This feature isn't mandatory, but higly recommended for security
|
25
|
+
# reasons.
|
26
|
+
#
|
27
|
+
# Because params come into your application from untrusted sources, it's
|
28
|
+
# a good practice to filter only the wanted keys that serve for your
|
29
|
+
# specific use case.
|
30
|
+
#
|
31
|
+
# Once whitelisted, the params are available as an Hash with symbols
|
32
|
+
# as keys.
|
33
|
+
#
|
34
|
+
#
|
35
|
+
#
|
36
|
+
# It accepts an anonymous block where all the params can be listed.
|
37
|
+
# It internally creates an inner class which inherits from
|
38
|
+
# Lotus::Action::Params.
|
39
|
+
#
|
40
|
+
#
|
41
|
+
# Alternatively, it accepts an concrete class that should inherit from
|
42
|
+
# Lotus::Action::Params.
|
43
|
+
#
|
44
|
+
# @param klass [Class,nil] a Lotus::Action::Params subclass
|
45
|
+
# @param blk [Proc] a block which defines the whitelisted params
|
46
|
+
#
|
47
|
+
# @return void
|
48
|
+
#
|
49
|
+
# @since 0.3.0
|
50
|
+
#
|
51
|
+
# @see Lotus::Action::Params
|
52
|
+
#
|
53
|
+
# @example Anonymous Block
|
54
|
+
# require 'lotus/controller'
|
55
|
+
#
|
56
|
+
# class Signup
|
57
|
+
# include Lotus::Action
|
58
|
+
#
|
59
|
+
# params do
|
60
|
+
# param :first_name
|
61
|
+
# param :last_name
|
62
|
+
# param :email
|
63
|
+
# end
|
64
|
+
#
|
65
|
+
# def call(params)
|
66
|
+
# puts params.class # => Signup::Params
|
67
|
+
# puts params.class.superclass # => Lotus::Action::Params
|
68
|
+
#
|
69
|
+
# puts params[:first_name] # => "Luca"
|
70
|
+
# puts params[:admin] # => nil
|
71
|
+
# end
|
72
|
+
# end
|
73
|
+
#
|
74
|
+
# @example Concrete class
|
75
|
+
# require 'lotus/controller'
|
76
|
+
#
|
77
|
+
# class SignupParams < Lotus::Action::Params
|
78
|
+
# param :first_name
|
79
|
+
# param :last_name
|
80
|
+
# param :email
|
81
|
+
# end
|
82
|
+
#
|
83
|
+
# class Signup
|
84
|
+
# include Lotus::Action
|
85
|
+
# params SignupParams
|
86
|
+
#
|
87
|
+
# def call(params)
|
88
|
+
# puts params.class # => SignupParams
|
89
|
+
# puts params.class.superclass # => Lotus::Action::Params
|
90
|
+
#
|
91
|
+
# params[:first_name] # => "Luca"
|
92
|
+
# params[:admin] # => nil
|
93
|
+
# end
|
94
|
+
# end
|
95
|
+
def params(klass = nil, &blk)
|
96
|
+
if block_given?
|
97
|
+
@params_class = const_set(PARAMS_CLASS_NAME,
|
98
|
+
Class.new(Params, &blk))
|
99
|
+
else
|
100
|
+
@params_class = klass
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
# Returns the class which defines the params
|
105
|
+
#
|
106
|
+
# Returns the class which has been provided to define the
|
107
|
+
# params. By default this will be Lotus::Action::Params.
|
108
|
+
#
|
109
|
+
# @return [Class] A params class (when whitelisted) or
|
110
|
+
# Lotus::Action::Params
|
111
|
+
#
|
112
|
+
# @api private
|
113
|
+
# @since 0.3.0
|
114
|
+
def params_class
|
115
|
+
@params_class ||= params { }
|
116
|
+
end
|
117
|
+
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
# Expose validation errors
|
122
|
+
#
|
123
|
+
# @since 0.3.0
|
124
|
+
def errors
|
125
|
+
params.errors
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
data/lib/lotus/controller.rb
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
require 'lotus/utils/class_attribute'
|
2
2
|
require 'lotus/action'
|
3
3
|
require 'lotus/controller/configuration'
|
4
|
-
require 'lotus/controller/dsl'
|
5
4
|
require 'lotus/controller/version'
|
6
5
|
require 'rack-patch'
|
7
6
|
|
@@ -15,14 +14,16 @@ module Lotus
|
|
15
14
|
# @example
|
16
15
|
# require 'lotus/controller'
|
17
16
|
#
|
18
|
-
#
|
19
|
-
#
|
17
|
+
# module Articles
|
18
|
+
# class Index
|
19
|
+
# include Lotus::Action
|
20
20
|
#
|
21
|
-
# action 'Index' do
|
22
21
|
# # ...
|
23
22
|
# end
|
24
23
|
#
|
25
|
-
#
|
24
|
+
# class Show
|
25
|
+
# include Lotus::Action
|
26
|
+
#
|
26
27
|
# # ...
|
27
28
|
# end
|
28
29
|
# end
|
@@ -241,28 +242,13 @@ module Lotus
|
|
241
242
|
end
|
242
243
|
end
|
243
244
|
|
244
|
-
#
|
245
|
-
# It includes basic Lotus::Controller modules to the given Class (or Module).
|
246
|
-
# It sets a copy of the framework configuration
|
247
|
-
#
|
248
|
-
# @param base [Class,Module] the target controller
|
249
|
-
#
|
250
|
-
# @since 0.1.0
|
251
|
-
# @api private
|
245
|
+
# Framework loading entry point
|
252
246
|
#
|
253
|
-
# @
|
247
|
+
# @return [void]
|
254
248
|
#
|
255
|
-
# @
|
256
|
-
def self.
|
257
|
-
|
258
|
-
|
259
|
-
base.class_eval do
|
260
|
-
include Dsl
|
261
|
-
include Utils::ClassAttribute
|
262
|
-
|
263
|
-
class_attribute :configuration
|
264
|
-
self.configuration = conf
|
265
|
-
end
|
249
|
+
# @since 0.3.0
|
250
|
+
def self.load!
|
251
|
+
configuration.load!
|
266
252
|
end
|
267
253
|
end
|
268
254
|
end
|
@@ -68,9 +68,9 @@ module Lotus
|
|
68
68
|
# Controller = Lotus::Controller.duplicate(self)
|
69
69
|
#
|
70
70
|
# module Controllers::Dashboard
|
71
|
-
#
|
71
|
+
# class Index
|
72
|
+
# include MyApp::Action
|
72
73
|
#
|
73
|
-
# action 'Index' do
|
74
74
|
# def call(params)
|
75
75
|
# # ...
|
76
76
|
# end
|
@@ -89,7 +89,7 @@ module Lotus
|
|
89
89
|
# # => will duplicate from MyApp::Controller
|
90
90
|
def self.for(base)
|
91
91
|
namespace = Utils::String.new(base).namespace
|
92
|
-
framework = Utils::Class.
|
92
|
+
framework = Utils::Class.load_from_pattern!("(#{namespace}|Lotus)::Controller")
|
93
93
|
framework.configuration.duplicate
|
94
94
|
end
|
95
95
|
|
@@ -103,15 +103,17 @@ module Lotus
|
|
103
103
|
reset!
|
104
104
|
end
|
105
105
|
|
106
|
-
# @attr_writer handle_exceptions [TrueClass,FalseClass]
|
107
|
-
#
|
106
|
+
# @attr_writer handle_exceptions [TrueClass,FalseClass] Handle exceptions
|
107
|
+
# with an HTTP status or leave them uncaught
|
108
108
|
#
|
109
109
|
# @since 0.2.0
|
110
110
|
#
|
111
|
+
# @return void
|
112
|
+
#
|
111
113
|
# @see Lotus::Controller::Configuration#handle_exceptions
|
112
114
|
attr_writer :handle_exceptions
|
113
115
|
|
114
|
-
#
|
116
|
+
# Handle exceptions with an HTTP status or let them uncaught
|
115
117
|
#
|
116
118
|
# If this value is set to `true`, the configured exceptions will return
|
117
119
|
# the specified HTTP status, the rest of them with `500`.
|
@@ -180,20 +182,16 @@ module Lotus
|
|
180
182
|
@handled_exceptions.merge!(exception)
|
181
183
|
end
|
182
184
|
|
183
|
-
# Return
|
184
|
-
#
|
185
|
-
# Raised exceptions will return the configured HTTP status, only if
|
186
|
-
# `handled_exceptions` is set on `true`.
|
185
|
+
# Return a callable handler for the given exception
|
187
186
|
#
|
188
|
-
# @param exception [
|
189
|
-
# status the value of the hash
|
187
|
+
# @param exception [Exception] an exception
|
190
188
|
#
|
191
|
-
# @since 0.
|
189
|
+
# @since 0.3.0
|
192
190
|
# @api private
|
193
191
|
#
|
194
192
|
# @see Lotus::Controller::Configuration#handle_exception
|
195
|
-
def
|
196
|
-
@handled_exceptions.fetch(exception) { DEFAULT_ERROR_CODE }
|
193
|
+
def exception_handler(exception)
|
194
|
+
@handled_exceptions.fetch(exception.class) { DEFAULT_ERROR_CODE }
|
197
195
|
end
|
198
196
|
|
199
197
|
# Specify which is the default action module to be included when we use
|
@@ -237,11 +235,11 @@ module Lotus
|
|
237
235
|
# action_module MyAction
|
238
236
|
# end
|
239
237
|
#
|
240
|
-
#
|
241
|
-
# include Lotus::Controller
|
242
|
-
#
|
238
|
+
# module Dashboard
|
243
239
|
# # It includes MyAction, instead of Lotus::Action
|
244
|
-
#
|
240
|
+
# class Index
|
241
|
+
# include MyAction
|
242
|
+
#
|
245
243
|
# def call(params)
|
246
244
|
# # ...
|
247
245
|
# end
|
@@ -258,7 +256,9 @@ module Lotus
|
|
258
256
|
# include MyApp::Controller
|
259
257
|
#
|
260
258
|
# # It includes MyApp::Action, instead of Lotus::Action
|
261
|
-
#
|
259
|
+
# class Index
|
260
|
+
# include MyApp::Action
|
261
|
+
#
|
262
262
|
# def call(params)
|
263
263
|
# # ...
|
264
264
|
# end
|
@@ -273,64 +273,54 @@ module Lotus
|
|
273
273
|
end
|
274
274
|
end
|
275
275
|
|
276
|
-
#
|
277
|
-
#
|
278
|
-
#
|
276
|
+
# Configure the logic to be executed when Lotus::Action is included
|
277
|
+
# This is useful to DRY code by having a single place where to configure
|
278
|
+
# shared behaviors like authentication, sessions, cookies etc.
|
279
279
|
#
|
280
|
-
#
|
280
|
+
# This method can be called multiple times.
|
281
281
|
#
|
282
|
-
#
|
283
|
-
# an argument, it will set the corresponding instance variable. When
|
284
|
-
# called without, it will return the already set value, or the default.
|
282
|
+
# @param blk [Proc] the code block
|
285
283
|
#
|
286
|
-
# @
|
287
|
-
# Adds the given block
|
288
|
-
# @param value [Proc] specify the modules to be included
|
284
|
+
# @return [void]
|
289
285
|
#
|
290
|
-
# @
|
291
|
-
# Gets the value
|
292
|
-
# @return [Array] the list of the specified procs
|
286
|
+
# @raise [ArgumentError] if called without passing a block
|
293
287
|
#
|
294
|
-
# @since 0.
|
288
|
+
# @since 0.3.0
|
295
289
|
#
|
296
|
-
# @see Lotus::Controller
|
297
|
-
# @see Lotus::Controller
|
298
|
-
#
|
299
|
-
# @example Getting the value
|
300
|
-
# require 'lotus/controller'
|
290
|
+
# @see Lotus::Controller.configure
|
291
|
+
# @see Lotus::Controller.duplicate
|
301
292
|
#
|
302
|
-
#
|
303
|
-
#
|
304
|
-
# @example Setting the value
|
293
|
+
# @example Configure shared logic.
|
305
294
|
# require 'lotus/controller'
|
306
|
-
# require 'lotus/action/cookies'
|
307
|
-
# require 'lotus/action/session'
|
308
295
|
#
|
309
296
|
# Lotus::Controller.configure do
|
310
|
-
#
|
311
|
-
# include Lotus::Action::
|
312
|
-
# include
|
297
|
+
# prepare do
|
298
|
+
# include Lotus::Action::Sessions
|
299
|
+
# include MyAuthentication
|
300
|
+
# use SomeMiddleWare
|
301
|
+
#
|
302
|
+
# before { authenticate! }
|
313
303
|
# end
|
314
304
|
# end
|
315
305
|
#
|
316
|
-
#
|
317
|
-
#
|
306
|
+
# module Dashboard
|
307
|
+
# class Index
|
308
|
+
# # When Lotus::Action is included, it will:
|
309
|
+
# # * Include `Lotus::Action::Session` and `MyAuthentication`
|
310
|
+
# # * Configure to use `SomeMiddleWare`
|
311
|
+
# # * Configure a `before` callback that triggers `#authenticate!`
|
312
|
+
# include Lotus::Action
|
318
313
|
#
|
319
|
-
# # It includes:
|
320
|
-
# # * Lotus::Action
|
321
|
-
# # * Lotus::Action::Cookies
|
322
|
-
# # * Lotus::Action::Session
|
323
|
-
# action 'Index' do
|
324
314
|
# def call(params)
|
325
315
|
# # ...
|
326
316
|
# end
|
327
317
|
# end
|
328
318
|
# end
|
329
|
-
def
|
319
|
+
def prepare(&blk)
|
330
320
|
if block_given?
|
331
321
|
@modules.push(blk)
|
332
322
|
else
|
333
|
-
|
323
|
+
raise ArgumentError.new('Please provide a block')
|
334
324
|
end
|
335
325
|
end
|
336
326
|
|
@@ -350,16 +340,18 @@ module Lotus
|
|
350
340
|
# format custom: 'application/custom'
|
351
341
|
# end
|
352
342
|
#
|
353
|
-
#
|
354
|
-
#
|
343
|
+
# module Articles
|
344
|
+
# class Index
|
345
|
+
# include Lotus::Action
|
355
346
|
#
|
356
|
-
# action 'Index' do
|
357
347
|
# def call(params)
|
358
348
|
# # ...
|
359
349
|
# end
|
360
350
|
# end
|
361
351
|
#
|
362
|
-
#
|
352
|
+
# class Show
|
353
|
+
# include Lotus::Action
|
354
|
+
#
|
363
355
|
# def call(params)
|
364
356
|
# # ...
|
365
357
|
# self.format = :custom
|
@@ -367,7 +359,7 @@ module Lotus
|
|
367
359
|
# end
|
368
360
|
# end
|
369
361
|
#
|
370
|
-
# action =
|
362
|
+
# action = Articles::Index.new
|
371
363
|
#
|
372
364
|
# action.call({ 'HTTP_ACCEPT' => 'text/html' })
|
373
365
|
# # => Content-Type "text/html"
|
@@ -379,7 +371,7 @@ module Lotus
|
|
379
371
|
#
|
380
372
|
#
|
381
373
|
#
|
382
|
-
# action =
|
374
|
+
# action = Articles::Show.new
|
383
375
|
#
|
384
376
|
# action.call({ 'HTTP_ACCEPT' => 'text/html' })
|
385
377
|
# # => Content-Type "application/custom"
|
@@ -395,7 +387,7 @@ module Lotus
|
|
395
387
|
# requirement for the mime type.
|
396
388
|
#
|
397
389
|
# The given format must be coercible to a symbol, and be a valid mime type
|
398
|
-
# alias. If it isn't, at the runtime the framework will raise a
|
390
|
+
# alias. If it isn't, at the runtime the framework will raise a
|
399
391
|
# `Lotus::Controller::UnknownFormatError`.
|
400
392
|
#
|
401
393
|
# By default this value is nil.
|
@@ -436,6 +428,34 @@ module Lotus
|
|
436
428
|
end
|
437
429
|
end
|
438
430
|
|
431
|
+
# Set a charset as default fallback for all the requests without a strict
|
432
|
+
# requirement for the charset.
|
433
|
+
#
|
434
|
+
# By default this value is nil.
|
435
|
+
#
|
436
|
+
# @since 0.3.0
|
437
|
+
#
|
438
|
+
# @see Lotus::Action::Mime
|
439
|
+
#
|
440
|
+
# @example Getting the value
|
441
|
+
# require 'lotus/controller'
|
442
|
+
#
|
443
|
+
# Lotus::Controller.configuration.default_charset # => nil
|
444
|
+
#
|
445
|
+
# @example Setting the value
|
446
|
+
# require 'lotus/controller'
|
447
|
+
#
|
448
|
+
# Lotus::Controller.configure do
|
449
|
+
# default_charset 'koi8-r'
|
450
|
+
# end
|
451
|
+
def default_charset(charset = nil)
|
452
|
+
if charset
|
453
|
+
@default_charset = charset
|
454
|
+
else
|
455
|
+
@default_charset
|
456
|
+
end
|
457
|
+
end
|
458
|
+
|
439
459
|
# Returns a format for the given mime type
|
440
460
|
#
|
441
461
|
# @param mime_type [#to_s,#to_str] A mime type
|
@@ -455,6 +475,9 @@ module Lotus
|
|
455
475
|
# @param format [#to_sym] a format
|
456
476
|
#
|
457
477
|
# @return [String,nil] the corresponding mime type, if present
|
478
|
+
#
|
479
|
+
# @since 0.2.0
|
480
|
+
# @api private
|
458
481
|
def mime_type_for(format)
|
459
482
|
@formats.key(format)
|
460
483
|
end
|
@@ -473,9 +496,20 @@ module Lotus
|
|
473
496
|
c.modules = modules.dup
|
474
497
|
c.formats = formats.dup
|
475
498
|
c.default_format = default_format
|
499
|
+
c.default_charset = default_charset
|
476
500
|
end
|
477
501
|
end
|
478
502
|
|
503
|
+
# Return included modules
|
504
|
+
#
|
505
|
+
# @return [Array<Proc>] array of included blocks
|
506
|
+
#
|
507
|
+
# @since 0.2.0
|
508
|
+
# @api private
|
509
|
+
#
|
510
|
+
# @see Lotus::Controller::Configuration#prepare
|
511
|
+
attr_reader :modules
|
512
|
+
|
479
513
|
# Reset all the values to the defaults
|
480
514
|
#
|
481
515
|
# @since 0.2.0
|
@@ -486,25 +520,42 @@ module Lotus
|
|
486
520
|
@modules = []
|
487
521
|
@formats = DEFAULT_FORMATS.dup
|
488
522
|
@default_format = nil
|
523
|
+
@default_charset = nil
|
489
524
|
@action_module = ::Lotus::Action
|
490
525
|
end
|
491
526
|
|
492
|
-
#
|
527
|
+
# Copy the configuration for the given action
|
493
528
|
#
|
494
|
-
# @
|
529
|
+
# @param base [Class] the target action
|
530
|
+
#
|
531
|
+
# @return void
|
532
|
+
#
|
533
|
+
# @since 0.3.0
|
495
534
|
# @api private
|
496
|
-
|
535
|
+
#
|
536
|
+
# @see Lotus::Controller::Configurable.included
|
537
|
+
def copy!(base)
|
497
538
|
modules.each do |mod|
|
498
539
|
base.class_eval(&mod)
|
499
540
|
end
|
500
541
|
end
|
501
542
|
|
543
|
+
# Load the framework
|
544
|
+
#
|
545
|
+
# @since 0.3.0
|
546
|
+
# @api private
|
547
|
+
def load!
|
548
|
+
freeze
|
549
|
+
end
|
550
|
+
|
502
551
|
protected
|
552
|
+
|
503
553
|
attr_accessor :handled_exceptions
|
504
554
|
attr_accessor :formats
|
505
555
|
attr_writer :action_module
|
506
556
|
attr_writer :modules
|
507
557
|
attr_writer :default_format
|
558
|
+
attr_writer :default_charset
|
508
559
|
end
|
509
560
|
end
|
510
561
|
end
|