action_handler 0.0.0 → 0.1.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
  SHA256:
3
- metadata.gz: 2cb17f485ca9bcfe1a0d3f8ccf1273d5a11dc0ab00f8fc24e46c4696f2c85d41
4
- data.tar.gz: 2a19b8f23d01be2202a3c4bc91797d25e94afeaa318e3c54f7f4f3c62ea2c2d6
3
+ metadata.gz: 06a9029c41b4a4ad4284e7e91f59724885da4f47b75b561cb30ed03f76734e19
4
+ data.tar.gz: ffbd72526d8bf9977a6807da8c10596db7b788d0596f50c558f216cc5af38f06
5
5
  SHA512:
6
- metadata.gz: e24ba8bc134de0cdec88fba626866666439db82f928dcda58cc6626bed09785ff99b938d2934eccee81651bfe8569daf49bba85c8fb2196bacffccc4f46d6435
7
- data.tar.gz: 9b5269ec69e02c98fbffa7e3221a5c89ad6699443e36a34f5d7747c26c84e5687e6695ffaaaf87a7053345d1666b3a2c96c5ebf9ea75056c5442a9523fcbc293
6
+ metadata.gz: be995c1aea5765076ec538b25558a67c7105aa212aa9432e3bf1a83cd0b76dd6a94019dd121dcc6b00e130f6e554aa7c0997aab98bd10c52df9635fead2ce409
7
+ data.tar.gz: fccdd48b45bf653d32a27165945c45c6c174ec8ee872a356b22271ce4946a01f86dc1edcc39257b31426e8c23ce66b69e46d4900fd28e8abd775b59f60633a05
data/README.md CHANGED
@@ -8,9 +8,9 @@ ActionHandler is a Rails plugin that helps you write controller functionalities
8
8
 
9
9
  A handler is a controller-like class. Each public method can be an action method.
10
10
  But unlike controllers, handlers inherit few methods by default.
11
- Intead of using super class methods such as `params`, `sessions`, you can take them as arguments.
11
+ Instead of using super class methods such as `params`, `sessions`, you can take them as arguments.
12
12
  And you need to represent a response (data for views) as a single return value,
13
- instead of assiging multiple instance variables.
13
+ instead of assigning multiple instance variables.
14
14
 
15
15
  ```ruby
16
16
  # Example
@@ -56,8 +56,7 @@ end
56
56
 
57
57
  ### Clean and clear structure
58
58
 
59
- - In handlers, action methods take necessary inputs as arguments and
60
- return output as a return value.
59
+ - In handlers, action methods take necessary inputs as arguments and represent output as a return value.
61
60
  So easy to read and test.
62
61
  - Handler is just a class, so you can set up any dependencies via `initialize` method.
63
62
 
@@ -67,7 +66,7 @@ end
67
66
  just by declaring them as action method's arguments.
68
67
  - You can define custom injectable arguments as well.
69
68
 
70
- Note that this feature is heavily inspired by [ActionArgs](https://github.com/asakusarb/action_args).
69
+ This feature is heavily inspired by [ActionArgs](https://github.com/asakusarb/action_args).
71
70
 
72
71
  ## Motivation
73
72
 
@@ -121,11 +120,8 @@ to use basic controller functionalities like `redirect_to` or custom arguments.
121
120
 
122
121
  ## Guides
123
122
 
124
- See [Wiki][wiki] for detailed guides.
123
+ - [Detail guides][wiki]
124
+ - [Example Rails app][example]
125
125
 
126
126
  [wiki]: https://github.com/ryym/action_handler/wiki
127
-
128
- TODO:
129
-
130
- - Currently Unsupported controller features
131
- - Where should handlers be placed?
127
+ [example]: https://github.com/ryym/action_handler/tree/master/examples/sample
@@ -1,18 +1,48 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActionHandler
4
- class ArgsMaker
5
- # TODO: Support optional arguments and keyword arguments.
4
+ class ActionArgumentError < StandardError
5
+ def initialize(method, details)
6
+ super("Arguments of #{method.owner.name}##{method.name} is invalid: #{details}")
7
+ end
8
+ end
6
9
 
7
- def make_args(parameters, supplier, context: nil)
10
+ class ArgsMaker
11
+ def make_args(method, supplier, context: nil)
8
12
  supplier_args = [context].compact
9
- parameters.inject([]) do |values, (_, name)|
13
+
14
+ values = []
15
+ keywords = {}
16
+
17
+ method.parameters.each do |kind, name|
10
18
  unless supplier.respond_to?(name)
11
- raise ArgumentError, "parameter #{name} is not defined in #{supplier}"
19
+ raise ActionHandler::ActionArgumentError.new(
20
+ method,
21
+ "parameter #{name} is not defined in #{supplier}",
22
+ )
12
23
  end
13
24
 
14
- values << supplier.send(name, *supplier_args)
25
+ case kind
26
+ when :req
27
+ values << supplier.send(name, *supplier_args)
28
+ when :keyreq
29
+ keywords[name] = supplier.send(name, *supplier_args)
30
+ when :opt, :key
31
+ raise ActionHandler::ActionArgumentError.new(method, <<~ERR)
32
+ Do not use optional arguments.
33
+ ActionHandler always injects arguments even if the value is nil,
34
+ so the optional values never be used.
35
+ ERR
36
+ when :rest, :keyrest
37
+ raise ActionHandler::ActionArgumentError.new(
38
+ method,
39
+ 'rest arguments cannot be used',
40
+ )
41
+ end
15
42
  end
43
+
44
+ values << keywords unless keywords.empty?
45
+ values
16
46
  end
17
47
  end
18
48
  end
@@ -14,24 +14,16 @@ module ActionHandler
14
14
  handler_class.instance_variable_set(CONFIG_VAR_NAME, config)
15
15
  end
16
16
 
17
- attr_reader :as_controller
18
17
  attr_reader :action_methods
19
18
  attr_reader :args_suppliers
20
19
  attr_reader :custom_args
21
20
 
22
21
  def initialize
23
- @as_controller = nil
24
22
  @action_methods = nil
25
23
  @args_suppliers = []
26
24
  @custom_args = {} # { method_name: proc }
27
25
  end
28
26
 
29
- def as_controller=(block)
30
- raise ArgumentError, 'must be proc' unless block.is_a?(Proc)
31
-
32
- @as_controller = block
33
- end
34
-
35
27
  def action_methods=(names)
36
28
  raise ArgumentError, 'must be array' unless names.is_a?(Array)
37
29
 
@@ -10,9 +10,8 @@ module ActionHandler
10
10
  end
11
11
 
12
12
  module ControllerExtension
13
- def use_handler
14
- handler = yield
15
- ActionHandler::Installer.new.install(handler, self)
13
+ def use_handler(&block)
14
+ ActionHandler::Installer.new.install(self, &block)
16
15
  end
17
16
  end
18
17
  end
@@ -35,10 +35,6 @@ module ActionHandler
35
35
  end
36
36
 
37
37
  module HandlerExtension
38
- def as_controller(&block)
39
- ActionHandler::Config.get(self).as_controller = block
40
- end
41
-
42
38
  def action_methods(*method_names)
43
39
  ActionHandler::Config.get(self).action_methods = method_names
44
40
  end
@@ -3,6 +3,11 @@
3
3
  require 'action_handler/args_maker'
4
4
  require 'action_handler/response_evaluator'
5
5
 
6
+ # TODO: Add `controller_send` (to use controller methods like `send_data`)
7
+
8
+ # It is better if there is a way to return streaming response.
9
+ # (`self.response_body = ` or `response.stream.write`?)
10
+
6
11
  module ActionHandler
7
12
  class Installer
8
13
  attr_reader :args_maker
@@ -16,23 +21,37 @@ module ActionHandler
16
21
  @res_evaluator = res_evaluator
17
22
  end
18
23
 
19
- def install(handler, ctrl_class)
20
- config = ActionHandler::Config.get(handler.class) || ActionHandler::Config.new
24
+ def install(ctrl_class, &block)
25
+ ctrl_class.instance_variable_set(:@_action_handler_factory, block)
26
+
27
+ installer = self
28
+ initializer = Module.new.tap do |m|
29
+ m.define_method(:initialize) do |*args|
30
+ super(*args)
31
+ factory = self.class.instance_variable_get(:@_action_handler_factory)
32
+ handler = factory.call(self)
33
+ installer.send(:setup, self, handler)
34
+ end
35
+ end
21
36
 
22
- ctrl_class.class_eval(&config.as_controller) if config.as_controller
37
+ ctrl_class.prepend initializer
38
+ end
39
+
40
+ private def setup(ctrl, handler)
41
+ config = ActionHandler::Config.get(handler.class) || ActionHandler::Config.new
23
42
 
24
43
  actions = action_methods(handler, config)
25
44
  args_supplier = args_supplier(config)
26
45
 
27
46
  actions.each do |name|
28
47
  installer = self
29
- ctrl_class.send(:define_method, name) do
48
+
49
+ # If we use `define_singleton_method`, methods don't work correctly.
50
+ # I don't know Rails internal details but
51
+ # Rails requires methods to be defined in a class.
52
+ ctrl.class.define_method(name) do
30
53
  method = handler.method(name)
31
- args = installer.args_maker.make_args(
32
- method.parameters,
33
- args_supplier,
34
- context: self,
35
- )
54
+ args = installer.args_maker.make_args(method, args_supplier, context: self)
36
55
  res = method.call(*args)
37
56
  installer.res_evaluator.evaluate(self, res)
38
57
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActionHandler
4
- VERSION = '0.0.0'
4
+ VERSION = '0.1.0'
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: action_handler
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.0
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - ryym
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-11-13 00:00:00.000000000 Z
11
+ date: 2018-12-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec
@@ -85,7 +85,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
85
85
  requirements:
86
86
  - - ">="
87
87
  - !ruby/object:Gem::Version
88
- version: '0'
88
+ version: '2.3'
89
89
  required_rubygems_version: !ruby/object:Gem::Requirement
90
90
  requirements:
91
91
  - - ">="