lino 3.2.0.pre.5 → 3.2.0.pre.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +93 -58
  3. data/lib/lino/builders/command_line.rb +59 -0
  4. data/lib/lino/builders/mixins/appliables.rb +27 -0
  5. data/lib/lino/builders/mixins/arguments.rb +38 -0
  6. data/lib/lino/builders/mixins/defaulting.rb +19 -0
  7. data/lib/lino/builders/mixins/environment_variables.rb +46 -0
  8. data/lib/lino/builders/mixins/executor.rb +24 -0
  9. data/lib/lino/builders/mixins/option_config.rb +50 -0
  10. data/lib/lino/builders/mixins/options.rb +118 -0
  11. data/lib/lino/builders/mixins/state_boundary.rb +22 -0
  12. data/lib/lino/builders/mixins/subcommands.rb +52 -0
  13. data/lib/lino/builders/mixins/validation.rb +21 -0
  14. data/lib/lino/builders/mixins/working_directory.rb +24 -0
  15. data/lib/lino/builders/subcommand.rb +47 -0
  16. data/lib/lino/builders.rb +9 -0
  17. data/lib/lino/errors/execution_error.rb +18 -0
  18. data/lib/lino/errors.rb +8 -0
  19. data/lib/lino/executors/childprocess.rb +63 -0
  20. data/lib/lino/executors/open4.rb +42 -0
  21. data/lib/lino/executors.rb +9 -0
  22. data/lib/lino/model/argument.rb +41 -0
  23. data/lib/lino/model/command_line.rb +117 -0
  24. data/lib/lino/model/environment_variable.rb +63 -0
  25. data/lib/lino/model/flag.rb +53 -0
  26. data/lib/lino/model/option.rb +73 -0
  27. data/lib/lino/model/subcommand.rb +52 -0
  28. data/lib/lino/model.rb +13 -0
  29. data/lib/lino/version.rb +1 -1
  30. data/lib/lino.rb +11 -2
  31. metadata +72 -10
  32. data/lib/lino/appliables.rb +0 -23
  33. data/lib/lino/command_line.rb +0 -28
  34. data/lib/lino/command_line_builder.rb +0 -225
  35. data/lib/lino/options.rb +0 -72
  36. data/lib/lino/subcommand_builder.rb +0 -49
  37. data/lib/lino/utilities.rb +0 -59
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: da1be1f8a40e20cd5496f4f9af92b3f43ac017b236577549d4c3e01fc1898a0a
4
- data.tar.gz: 1fb4703bb28986495300db42aded5e723416484ab4e19d81535905e1df9d3249
3
+ metadata.gz: b1dd66849dd6c056a887e3db11f3b7e4ce81fe79977803e756295b432782990d
4
+ data.tar.gz: dd084ea5d3d3e2399e17e3bf560fd5452094623218c0b3124e4ed2749e9abfc7
5
5
  SHA512:
6
- metadata.gz: 9ce392e4ecdfac6479022e409e8217962e6f44f4abebda2b75235d05a39f97e8dd2e5c4b532ffde6905777b424e1efe5067cd7c1bfc4b88e3f01e9aa0f9b8d7d
7
- data.tar.gz: 57d8859bc96f0243495829a2e555c741613345cb6618fc371a86aaaccea95005d4734a106139b3e7e4308fd8bde7a3d057aafa854218c20cfd08b3364db2f4c0
6
+ metadata.gz: efbe7f4fea738bceb5ae5e148de4591e0a635a0c67923e30eb69f9503723d2bb70eb28911fd1addde172218d217de1cb27a9d3237293759b323a341c964ba3af
7
+ data.tar.gz: 38833fa7c9b6c9c91e1056099fa4f3d0fe35117c624cb20bc7e265ad234a27613fa5f8f13176a148b0690bf60368d4919a0263d455e1faebdb1922801548995c
data/Gemfile.lock CHANGED
@@ -1,14 +1,15 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- lino (3.2.0.pre.5)
4
+ lino (3.2.0.pre.6)
5
+ childprocess (~> 5.0.0)
5
6
  hamster (~> 3.0)
6
7
  open4 (~> 1.3)
7
8
 
8
9
  GEM
9
10
  remote: https://rubygems.org/
10
11
  specs:
11
- activesupport (7.1.1)
12
+ activesupport (7.1.3.4)
12
13
  base64
13
14
  bigdecimal
14
15
  concurrent-ruby (~> 1.0, >= 1.0.2)
@@ -18,49 +19,80 @@ GEM
18
19
  minitest (>= 5.1)
19
20
  mutex_m
20
21
  tzinfo (~> 2.0)
21
- addressable (2.8.5)
22
- public_suffix (>= 2.0.2, < 6.0)
22
+ addressable (2.8.7)
23
+ public_suffix (>= 2.0.2, < 7.0)
23
24
  ast (2.4.2)
24
- base64 (0.1.1)
25
- bigdecimal (3.1.4)
25
+ base64 (0.2.0)
26
+ bigdecimal (3.1.8)
27
+ childprocess (5.0.0)
28
+ coderay (1.1.3)
26
29
  colored2 (3.1.2)
27
- concurrent-ruby (1.2.2)
30
+ concurrent-ruby (1.3.3)
28
31
  connection_pool (2.4.1)
29
- diff-lcs (1.5.0)
32
+ diff-lcs (1.5.1)
30
33
  docile (1.4.0)
31
- drb (2.1.1)
32
- ruby2_keywords
33
- excon (0.104.0)
34
- faraday (2.7.11)
35
- base64
36
- faraday-net_http (>= 2.0, < 3.1)
37
- ruby2_keywords (>= 0.0.4)
38
- faraday-net_http (3.0.2)
34
+ drb (2.2.1)
35
+ excon (0.110.0)
36
+ faraday (2.9.2)
37
+ faraday-net_http (>= 2.0, < 3.2)
38
+ faraday-net_http (3.1.0)
39
+ net-http
40
+ ffi (1.17.0)
41
+ formatador (1.1.0)
39
42
  gem-release (2.2.2)
40
- git (1.18.0)
43
+ git (1.19.1)
41
44
  addressable (~> 2.8)
42
45
  rchardet (~> 1.8)
46
+ guard (2.18.1)
47
+ formatador (>= 0.2.4)
48
+ listen (>= 2.7, < 4.0)
49
+ lumberjack (>= 1.0.12, < 2.0)
50
+ nenv (~> 0.1)
51
+ notiffany (~> 0.0)
52
+ pry (>= 0.13.0)
53
+ shellany (~> 0.0)
54
+ thor (>= 0.18.1)
55
+ guard-compat (1.2.1)
56
+ guard-rspec (4.7.3)
57
+ guard (~> 2.1)
58
+ guard-compat (~> 1.1)
59
+ rspec (>= 2.99.0, < 4.0)
43
60
  hamster (3.0.0)
44
61
  concurrent-ruby (~> 1.0)
45
- i18n (1.14.1)
62
+ i18n (1.14.5)
46
63
  concurrent-ruby (~> 1.0)
47
64
  immutable-struct (2.4.1)
48
- json (2.6.3)
65
+ json (2.7.2)
49
66
  language_server-protocol (3.17.0.3)
50
- minitest (5.20.0)
51
- mutex_m (0.1.2)
52
- octokit (8.0.0)
67
+ listen (3.9.0)
68
+ rb-fsevent (~> 0.10, >= 0.10.3)
69
+ rb-inotify (~> 0.9, >= 0.9.10)
70
+ lumberjack (1.2.10)
71
+ method_source (1.1.0)
72
+ minitest (5.24.1)
73
+ mutex_m (0.2.0)
74
+ nenv (0.3.0)
75
+ net-http (0.4.1)
76
+ uri
77
+ notiffany (0.1.3)
78
+ nenv (~> 0.1)
79
+ shellany (~> 0.0)
80
+ octokit (8.1.0)
81
+ base64
53
82
  faraday (>= 1, < 3)
54
83
  sawyer (~> 0.9)
55
84
  open4 (1.3.4)
56
- parallel (1.23.0)
57
- parser (3.2.2.4)
85
+ parallel (1.25.1)
86
+ parser (3.3.3.0)
58
87
  ast (~> 2.4.1)
59
88
  racc
60
- public_suffix (5.0.3)
61
- racc (1.7.3)
89
+ pry (0.14.2)
90
+ coderay (~> 1.1)
91
+ method_source (~> 1.0)
92
+ public_suffix (6.0.0)
93
+ racc (1.8.0)
62
94
  rainbow (3.1.1)
63
- rake (13.1.0)
95
+ rake (13.2.1)
64
96
  rake_circle_ci (0.11.0)
65
97
  colored2 (~> 3.1)
66
98
  excon (~> 0.72)
@@ -69,14 +101,14 @@ GEM
69
101
  rake_factory (0.32.0.pre.2)
70
102
  activesupport (>= 4)
71
103
  rake (~> 13.0)
72
- rake_git (0.1.0.pre.9)
104
+ rake_git (0.1.0.pre.10)
73
105
  colored2 (~> 3.1)
74
106
  git (~> 1.13, >= 1.13.2)
75
107
  rake_factory (= 0.32.0.pre.2)
76
- rake_git_crypt (0.1.0.pre.28)
108
+ rake_git_crypt (0.1.0.pre.29)
77
109
  colored2 (~> 3.1)
78
110
  rake_factory (= 0.32.0.pre.2)
79
- ruby_git_crypt (= 0.1.0.pre.2)
111
+ ruby_git_crypt (= 0.1.0.pre.4)
80
112
  ruby_gpg2 (~> 0.6)
81
113
  rake_github (0.13.0)
82
114
  colored2 (~> 3.1)
@@ -90,48 +122,45 @@ GEM
90
122
  colored2 (~> 3.1)
91
123
  rake_factory (~> 0.23)
92
124
  sshkey (~> 2.0)
125
+ rb-fsevent (0.11.2)
126
+ rb-inotify (0.11.1)
127
+ ffi (~> 1.0)
93
128
  rchardet (1.8.0)
94
- regexp_parser (2.8.2)
95
- rexml (3.2.6)
96
- rspec (3.12.0)
97
- rspec-core (~> 3.12.0)
98
- rspec-expectations (~> 3.12.0)
99
- rspec-mocks (~> 3.12.0)
100
- rspec-core (3.12.2)
101
- rspec-support (~> 3.12.0)
102
- rspec-expectations (3.12.3)
129
+ regexp_parser (2.9.2)
130
+ rexml (3.3.1)
131
+ strscan
132
+ rspec (3.13.0)
133
+ rspec-core (~> 3.13.0)
134
+ rspec-expectations (~> 3.13.0)
135
+ rspec-mocks (~> 3.13.0)
136
+ rspec-core (3.13.0)
137
+ rspec-support (~> 3.13.0)
138
+ rspec-expectations (3.13.1)
103
139
  diff-lcs (>= 1.2.0, < 2.0)
104
- rspec-support (~> 3.12.0)
105
- rspec-mocks (3.12.6)
140
+ rspec-support (~> 3.13.0)
141
+ rspec-mocks (3.13.1)
106
142
  diff-lcs (>= 1.2.0, < 2.0)
107
- rspec-support (~> 3.12.0)
108
- rspec-support (3.12.1)
109
- rubocop (1.57.2)
143
+ rspec-support (~> 3.13.0)
144
+ rspec-support (3.13.1)
145
+ rubocop (1.64.1)
110
146
  json (~> 2.3)
111
147
  language_server-protocol (>= 3.17.0)
112
148
  parallel (~> 1.10)
113
- parser (>= 3.2.2.4)
149
+ parser (>= 3.3.0.2)
114
150
  rainbow (>= 2.2.2, < 4.0)
115
151
  regexp_parser (>= 1.8, < 3.0)
116
152
  rexml (>= 3.2.5, < 4.0)
117
- rubocop-ast (>= 1.28.1, < 2.0)
153
+ rubocop-ast (>= 1.31.1, < 2.0)
118
154
  ruby-progressbar (~> 1.7)
119
155
  unicode-display_width (>= 2.4.0, < 3.0)
120
- rubocop-ast (1.30.0)
121
- parser (>= 3.2.1.0)
122
- rubocop-capybara (2.19.0)
123
- rubocop (~> 1.41)
124
- rubocop-factory_bot (2.24.0)
125
- rubocop (~> 1.33)
156
+ rubocop-ast (1.31.3)
157
+ parser (>= 3.3.1.0)
126
158
  rubocop-rake (0.6.0)
127
159
  rubocop (~> 1.0)
128
- rubocop-rspec (2.25.0)
129
- rubocop (~> 1.40)
130
- rubocop-capybara (~> 2.17)
131
- rubocop-factory_bot (~> 2.22)
160
+ rubocop-rspec (3.0.2)
161
+ rubocop (~> 1.61)
132
162
  ruby-progressbar (1.13.0)
133
- ruby2_keywords (0.0.5)
134
- ruby_git_crypt (0.1.0.pre.2)
163
+ ruby_git_crypt (0.1.0.pre.4)
135
164
  immutable-struct (~> 2.4)
136
165
  lino (~> 3.0)
137
166
  ruby_gpg2 (0.10.0)
@@ -139,6 +168,7 @@ GEM
139
168
  sawyer (0.9.2)
140
169
  addressable (>= 2.3.5)
141
170
  faraday (>= 0.17.3, < 3)
171
+ shellany (0.0.1)
142
172
  simplecov (0.22.0)
143
173
  docile (~> 1.1)
144
174
  simplecov-html (~> 0.11)
@@ -146,9 +176,12 @@ GEM
146
176
  simplecov-html (0.12.3)
147
177
  simplecov_json_formatter (0.1.4)
148
178
  sshkey (2.0.0)
179
+ strscan (3.1.0)
180
+ thor (1.3.1)
149
181
  tzinfo (2.0.6)
150
182
  concurrent-ruby (~> 1.0)
151
183
  unicode-display_width (2.5.0)
184
+ uri (0.13.0)
152
185
 
153
186
  PLATFORMS
154
187
  ruby
@@ -156,6 +189,8 @@ PLATFORMS
156
189
  DEPENDENCIES
157
190
  bundler
158
191
  gem-release
192
+ guard
193
+ guard-rspec
159
194
  lino!
160
195
  rake
161
196
  rake_circle_ci
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'hamster'
4
+
5
+ require_relative 'mixins/appliables'
6
+ require_relative 'mixins/arguments'
7
+ require_relative 'mixins/environment_variables'
8
+ require_relative 'mixins/executor'
9
+ require_relative 'mixins/option_config'
10
+ require_relative 'mixins/options'
11
+ require_relative 'mixins/state_boundary'
12
+ require_relative 'mixins/subcommands'
13
+ require_relative 'mixins/validation'
14
+ require_relative 'mixins/working_directory'
15
+ require_relative '../model'
16
+
17
+ module Lino
18
+ module Builders
19
+ class CommandLine
20
+ include Mixins::StateBoundary
21
+ include Mixins::Arguments
22
+ include Mixins::EnvironmentVariables
23
+ include Mixins::OptionConfig
24
+ include Mixins::Options
25
+ include Mixins::Subcommands
26
+ include Mixins::Executor
27
+ include Mixins::WorkingDirectory
28
+ include Mixins::Appliables
29
+ include Mixins::Validation
30
+
31
+ def initialize(state)
32
+ @command = state[:command]
33
+ super
34
+ end
35
+
36
+ def build
37
+ Model::CommandLine.new(
38
+ @command,
39
+ state.merge(
40
+ options: build_options,
41
+ subcommands: build_subcommands
42
+ )
43
+ )
44
+ end
45
+
46
+ protected
47
+
48
+ def state
49
+ super.merge(command: @command)
50
+ end
51
+
52
+ private
53
+
54
+ def with(replacements)
55
+ Builders::CommandLine.new(state.merge(replacements))
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'validation'
4
+
5
+ module Lino
6
+ module Builders
7
+ module Mixins
8
+ module Appliables
9
+ include Validation
10
+
11
+ def with_appliable(appliable)
12
+ return self if nil?(appliable)
13
+
14
+ appliable.apply(self)
15
+ end
16
+
17
+ def with_appliables(appliables)
18
+ return self if nil_or_empty?(appliables)
19
+
20
+ appliables.inject(self) do |s, appliable|
21
+ s.with_appliable(appliable)
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'validation'
4
+ require_relative '../../model'
5
+
6
+ module Lino
7
+ module Builders
8
+ module Mixins
9
+ module Arguments
10
+ include Validation
11
+
12
+ def initialize(state)
13
+ @arguments = Hamster::Vector.new(state[:arguments] || [])
14
+ super
15
+ end
16
+
17
+ def with_argument(argument)
18
+ return self if nil?(argument)
19
+ return self if empty?(argument.to_s)
20
+
21
+ with(arguments: @arguments.add(Model::Argument.new(argument)))
22
+ end
23
+
24
+ def with_arguments(arguments)
25
+ return self if nil_or_empty?(arguments)
26
+
27
+ arguments.inject(self) { |s, argument| s.with_argument(argument) }
28
+ end
29
+
30
+ private
31
+
32
+ def state
33
+ super.merge(arguments: @arguments)
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Lino
4
+ module Builders
5
+ module Mixins
6
+ module Defaulting
7
+ private
8
+
9
+ def or_nil(enumerable, key)
10
+ enumerable.include?(key) ? enumerable[key] : nil
11
+ end
12
+
13
+ def or_nth(enumerable, key, index)
14
+ enumerable.include?(key) ? enumerable[key] : enumerable[index]
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'validation'
4
+ require_relative '../../model'
5
+
6
+ module Lino
7
+ module Builders
8
+ module Mixins
9
+ module EnvironmentVariables
10
+ include Validation
11
+
12
+ def initialize(state)
13
+ @environment_variables =
14
+ Hamster::Vector.new(state[:environment_variables] || [])
15
+ super
16
+ end
17
+
18
+ def with_environment_variable(environment_variable, value)
19
+ with(
20
+ environment_variables:
21
+ @environment_variables.add(
22
+ Model::EnvironmentVariable.new(environment_variable, value)
23
+ )
24
+ )
25
+ end
26
+
27
+ def with_environment_variables(environment_variables)
28
+ return self if nil_or_empty?(environment_variables)
29
+
30
+ environment_variables.entries.inject(self) do |s, var|
31
+ s.with_environment_variable(
32
+ var.include?(:name) ? var[:name] : var[0],
33
+ var.include?(:value) ? var[:value] : var[1]
34
+ )
35
+ end
36
+ end
37
+
38
+ private
39
+
40
+ def state
41
+ super.merge(environment_variables: @environment_variables)
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Lino
4
+ module Builders
5
+ module Mixins
6
+ module Executor
7
+ def initialize(state)
8
+ @executor = state[:executor] || Executors::Childprocess.new
9
+ super
10
+ end
11
+
12
+ def with_executor(executor)
13
+ with(executor:)
14
+ end
15
+
16
+ private
17
+
18
+ def state
19
+ super.merge(executor: @executor)
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Lino
4
+ module Builders
5
+ module Mixins
6
+ module OptionConfig
7
+ def initialize(state)
8
+ @option_separator = state[:option_separator] || ' '
9
+ @option_quoting = state[:option_quoting]
10
+ @option_placement = state[:option_placement] || :after_command
11
+ super
12
+ end
13
+
14
+ def with_option_separator(option_separator)
15
+ with(option_separator:)
16
+ end
17
+
18
+ def with_option_quoting(character)
19
+ with(option_quoting: character)
20
+ end
21
+
22
+ def with_option_placement(option_placement)
23
+ with(option_placement:)
24
+ end
25
+
26
+ def with_options_after_command
27
+ with_option_placement(:after_command)
28
+ end
29
+
30
+ def with_options_after_subcommands
31
+ with_option_placement(:after_subcommands)
32
+ end
33
+
34
+ def with_options_after_arguments
35
+ with_option_placement(:after_arguments)
36
+ end
37
+
38
+ private
39
+
40
+ def state
41
+ super.merge(
42
+ option_separator: @option_separator,
43
+ option_quoting: @option_quoting,
44
+ option_placement: @option_placement
45
+ )
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,118 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../model'
4
+ require_relative 'validation'
5
+ require_relative 'defaulting'
6
+
7
+ module Lino
8
+ module Builders
9
+ module Mixins
10
+ module Options
11
+ include Validation
12
+ include Defaulting
13
+
14
+ def initialize(state)
15
+ @options = Hamster::Vector.new(state[:options] || [])
16
+ super
17
+ end
18
+
19
+ def with_option(
20
+ option,
21
+ value,
22
+ separator: nil,
23
+ quoting: nil,
24
+ placement: nil
25
+ )
26
+ return self if nil?(value)
27
+
28
+ with(options: @options.add(
29
+ {
30
+ type: :option,
31
+ components: [option, value],
32
+ separator:,
33
+ quoting:,
34
+ placement:
35
+ }
36
+ ))
37
+ end
38
+
39
+ def with_options(options)
40
+ return self if nil_or_empty?(options)
41
+
42
+ options.entries.inject(self) do |s, entry|
43
+ s.with_option(
44
+ or_nth(entry, :option, 0),
45
+ or_nth(entry, :value, 1),
46
+ separator: or_nil(entry, :separator),
47
+ quoting: or_nil(entry, :quoting),
48
+ placement: or_nil(entry, :placement)
49
+ )
50
+ end
51
+ end
52
+
53
+ def with_repeated_option(
54
+ option,
55
+ values,
56
+ separator: nil,
57
+ quoting: nil,
58
+ placement: nil
59
+ )
60
+ values.inject(self) do |s, value|
61
+ s.with_option(
62
+ option,
63
+ value,
64
+ separator:,
65
+ quoting:,
66
+ placement:
67
+ )
68
+ end
69
+ end
70
+
71
+ def with_flag(flag)
72
+ return self if nil?(flag)
73
+
74
+ with(options: @options.add(
75
+ {
76
+ type: :flag,
77
+ components: [flag]
78
+ }
79
+ ))
80
+ end
81
+
82
+ def with_flags(flags)
83
+ return self if nil_or_empty?(flags)
84
+
85
+ flags.inject(self) { |s, flag| s.with_flag(flag) }
86
+ end
87
+
88
+ private
89
+
90
+ def state
91
+ super.merge(options: @options)
92
+ end
93
+
94
+ def build_options
95
+ @options.map do |data|
96
+ data[:type] == :option ? build_option(data) : build_flag(data)
97
+ end
98
+ end
99
+
100
+ def build_option(option_data)
101
+ Model::Option.new(
102
+ *option_data[:components],
103
+ separator: option_data[:separator] || @option_separator,
104
+ quoting: option_data[:quoting] || @option_quoting,
105
+ placement: option_data[:placement] || @option_placement
106
+ )
107
+ end
108
+
109
+ def build_flag(flag_data)
110
+ Model::Flag.new(
111
+ *flag_data[:components],
112
+ placement: flag_data[:placement] || @option_placement
113
+ )
114
+ end
115
+ end
116
+ end
117
+ end
118
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'validation'
4
+ require_relative '../../model'
5
+
6
+ module Lino
7
+ module Builders
8
+ module Mixins
9
+ module StateBoundary
10
+ def initialize(_state)
11
+ super()
12
+ end
13
+
14
+ private
15
+
16
+ def state
17
+ {}
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end