action_handler 0.0.0 → 0.1.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
  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
  - - ">="