protos-protoform 0.0.1
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 +7 -0
- data/.rspec +3 -0
- data/.rubocop.yml +9 -0
- data/CHANGELOG.md +5 -0
- data/Gemfile +13 -0
- data/Gemfile.lock +245 -0
- data/LICENSE.txt +21 -0
- data/README.md +61 -0
- data/Rakefile +8 -0
- data/lib/generators/protoform/install/USAGE +8 -0
- data/lib/generators/protoform/install/install_generator.rb +39 -0
- data/lib/generators/protoform/install/templates/application_form.rb +36 -0
- data/lib/protoform/dom.rb +60 -0
- data/lib/protoform/field.rb +38 -0
- data/lib/protoform/field_collection.rb +39 -0
- data/lib/protoform/namespace.rb +159 -0
- data/lib/protoform/namespace_collection.rb +77 -0
- data/lib/protoform/node.rb +14 -0
- data/lib/protoform/rails/components/button.rb +28 -0
- data/lib/protoform/rails/components/checkbox.rb +28 -0
- data/lib/protoform/rails/components/component.rb +15 -0
- data/lib/protoform/rails/components/field_component.rb +18 -0
- data/lib/protoform/rails/components/input.rb +42 -0
- data/lib/protoform/rails/components/label.rb +22 -0
- data/lib/protoform/rails/components/select.rb +72 -0
- data/lib/protoform/rails/components/textarea.rb +14 -0
- data/lib/protoform/rails/form/field.rb +62 -0
- data/lib/protoform/rails/form.rb +121 -0
- data/lib/protoform/rails/option_mapper.rb +40 -0
- data/lib/protoform/rails/strong_parameters.rb +19 -0
- data/lib/protoform/version.rb +5 -0
- data/lib/protoform.rb +22 -0
- data/protos-protoform.gemspec +49 -0
- metadata +122 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: c57b1b4645f529c7f8b132e92b0776a839448cd20eb3c689fbcf3689f2f7cfda
|
4
|
+
data.tar.gz: da70f9680fed7bb2815deaa61ffb049ab9edfac706bb9e8b9e60f2ac8e5904a4
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 7dbee5d770d7efed179c43eb39892f8bf4fc8d7935b65160ab84876688a64bb3612a2226ffb421094c32412e895af9fbfcebe44872b54680b2cd7951f9d82c4d
|
7
|
+
data.tar.gz: 8bd336c38077d8c15855329c01c63a9897320b62117e06a4f747b7f2f3e9c9849b4bf37a0bd4bce8d854e9994fd6c0fa19ba0551e2275ee8511ac57d4dab1bfa
|
data/.rspec
ADDED
data/.rubocop.yml
ADDED
data/CHANGELOG.md
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,245 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
protos-protoform (0.0.1)
|
5
|
+
phlex-rails (~> 1.0)
|
6
|
+
protos (~> 0.2)
|
7
|
+
zeitwerk (~> 2.6)
|
8
|
+
|
9
|
+
GEM
|
10
|
+
remote: https://rubygems.org/
|
11
|
+
specs:
|
12
|
+
actionpack (7.1.3.2)
|
13
|
+
actionview (= 7.1.3.2)
|
14
|
+
activesupport (= 7.1.3.2)
|
15
|
+
nokogiri (>= 1.8.5)
|
16
|
+
racc
|
17
|
+
rack (>= 2.2.4)
|
18
|
+
rack-session (>= 1.0.1)
|
19
|
+
rack-test (>= 0.6.3)
|
20
|
+
rails-dom-testing (~> 2.2)
|
21
|
+
rails-html-sanitizer (~> 1.6)
|
22
|
+
actionview (7.1.3.2)
|
23
|
+
activesupport (= 7.1.3.2)
|
24
|
+
builder (~> 3.1)
|
25
|
+
erubi (~> 1.11)
|
26
|
+
rails-dom-testing (~> 2.2)
|
27
|
+
rails-html-sanitizer (~> 1.6)
|
28
|
+
activemodel (7.1.3.2)
|
29
|
+
activesupport (= 7.1.3.2)
|
30
|
+
activesupport (7.1.3.2)
|
31
|
+
base64
|
32
|
+
bigdecimal
|
33
|
+
concurrent-ruby (~> 1.0, >= 1.0.2)
|
34
|
+
connection_pool (>= 2.2.5)
|
35
|
+
drb
|
36
|
+
i18n (>= 1.6, < 2)
|
37
|
+
minitest (>= 5.1)
|
38
|
+
mutex_m
|
39
|
+
tzinfo (~> 2.0)
|
40
|
+
addressable (2.8.6)
|
41
|
+
public_suffix (>= 2.0.2, < 6.0)
|
42
|
+
ast (2.4.2)
|
43
|
+
base64 (0.2.0)
|
44
|
+
bigdecimal (3.1.7)
|
45
|
+
builder (3.2.4)
|
46
|
+
capybara (3.40.0)
|
47
|
+
addressable
|
48
|
+
matrix
|
49
|
+
mini_mime (>= 0.1.3)
|
50
|
+
nokogiri (~> 1.11)
|
51
|
+
rack (>= 1.6.0)
|
52
|
+
rack-test (>= 0.6.3)
|
53
|
+
regexp_parser (>= 1.5, < 3.0)
|
54
|
+
xpath (~> 3.2)
|
55
|
+
concurrent-ruby (1.2.3)
|
56
|
+
connection_pool (2.4.1)
|
57
|
+
crass (1.0.6)
|
58
|
+
debug (1.9.2)
|
59
|
+
irb (~> 1.10)
|
60
|
+
reline (>= 0.3.8)
|
61
|
+
diff-lcs (1.5.1)
|
62
|
+
drb (2.2.1)
|
63
|
+
dry-core (1.0.1)
|
64
|
+
concurrent-ruby (~> 1.0)
|
65
|
+
zeitwerk (~> 2.6)
|
66
|
+
dry-inflector (1.0.0)
|
67
|
+
dry-initializer (3.1.1)
|
68
|
+
dry-logic (1.5.0)
|
69
|
+
concurrent-ruby (~> 1.0)
|
70
|
+
dry-core (~> 1.0, < 2)
|
71
|
+
zeitwerk (~> 2.6)
|
72
|
+
dry-types (1.7.2)
|
73
|
+
bigdecimal (~> 3.0)
|
74
|
+
concurrent-ruby (~> 1.0)
|
75
|
+
dry-core (~> 1.0)
|
76
|
+
dry-inflector (~> 1.0)
|
77
|
+
dry-logic (~> 1.4)
|
78
|
+
zeitwerk (~> 2.6)
|
79
|
+
erubi (1.12.0)
|
80
|
+
i18n (1.14.4)
|
81
|
+
concurrent-ruby (~> 1.0)
|
82
|
+
io-console (0.7.2)
|
83
|
+
irb (1.12.0)
|
84
|
+
rdoc
|
85
|
+
reline (>= 0.4.2)
|
86
|
+
json (2.7.2)
|
87
|
+
language_server-protocol (3.17.0.3)
|
88
|
+
loofah (2.22.0)
|
89
|
+
crass (~> 1.0.2)
|
90
|
+
nokogiri (>= 1.12.0)
|
91
|
+
lru_redux (1.1.0)
|
92
|
+
matrix (0.4.2)
|
93
|
+
mini_mime (1.1.5)
|
94
|
+
minitest (5.22.3)
|
95
|
+
mutex_m (0.2.0)
|
96
|
+
nokogiri (1.16.4-aarch64-linux)
|
97
|
+
racc (~> 1.4)
|
98
|
+
nokogiri (1.16.4-arm-linux)
|
99
|
+
racc (~> 1.4)
|
100
|
+
nokogiri (1.16.4-arm64-darwin)
|
101
|
+
racc (~> 1.4)
|
102
|
+
nokogiri (1.16.4-x86-linux)
|
103
|
+
racc (~> 1.4)
|
104
|
+
nokogiri (1.16.4-x86_64-darwin)
|
105
|
+
racc (~> 1.4)
|
106
|
+
nokogiri (1.16.4-x86_64-linux)
|
107
|
+
racc (~> 1.4)
|
108
|
+
parallel (1.24.0)
|
109
|
+
parser (3.3.0.5)
|
110
|
+
ast (~> 2.4.1)
|
111
|
+
racc
|
112
|
+
phlex (1.10.0)
|
113
|
+
phlex-rails (1.2.1)
|
114
|
+
phlex (~> 1.10.0)
|
115
|
+
railties (>= 6.1, < 8)
|
116
|
+
phlex-testing-capybara (0.1.0)
|
117
|
+
capybara (~> 3.38)
|
118
|
+
phlex (>= 0.5)
|
119
|
+
protos (0.4.1)
|
120
|
+
dry-core (~> 1.0)
|
121
|
+
dry-initializer (~> 3.1)
|
122
|
+
dry-types (~> 1.7)
|
123
|
+
phlex (~> 1.10)
|
124
|
+
tailwind_merge (~> 0.10)
|
125
|
+
psych (5.1.2)
|
126
|
+
stringio
|
127
|
+
public_suffix (5.0.5)
|
128
|
+
racc (1.7.3)
|
129
|
+
rack (3.0.10)
|
130
|
+
rack-session (2.0.0)
|
131
|
+
rack (>= 3.0.0)
|
132
|
+
rack-test (2.1.0)
|
133
|
+
rack (>= 1.3)
|
134
|
+
rackup (2.1.0)
|
135
|
+
rack (>= 3)
|
136
|
+
webrick (~> 1.8)
|
137
|
+
rails-dom-testing (2.2.0)
|
138
|
+
activesupport (>= 5.0.0)
|
139
|
+
minitest
|
140
|
+
nokogiri (>= 1.6)
|
141
|
+
rails-html-sanitizer (1.6.0)
|
142
|
+
loofah (~> 2.21)
|
143
|
+
nokogiri (~> 1.14)
|
144
|
+
railties (7.1.3.2)
|
145
|
+
actionpack (= 7.1.3.2)
|
146
|
+
activesupport (= 7.1.3.2)
|
147
|
+
irb
|
148
|
+
rackup (>= 1.0.0)
|
149
|
+
rake (>= 12.2)
|
150
|
+
thor (~> 1.0, >= 1.2.2)
|
151
|
+
zeitwerk (~> 2.6)
|
152
|
+
rainbow (3.1.1)
|
153
|
+
rake (13.2.1)
|
154
|
+
rdoc (6.6.3.1)
|
155
|
+
psych (>= 4.0.0)
|
156
|
+
regexp_parser (2.9.0)
|
157
|
+
reline (0.5.1)
|
158
|
+
io-console (~> 0.5)
|
159
|
+
rexml (3.2.6)
|
160
|
+
rspec (3.13.0)
|
161
|
+
rspec-core (~> 3.13.0)
|
162
|
+
rspec-expectations (~> 3.13.0)
|
163
|
+
rspec-mocks (~> 3.13.0)
|
164
|
+
rspec-core (3.13.0)
|
165
|
+
rspec-support (~> 3.13.0)
|
166
|
+
rspec-expectations (3.13.0)
|
167
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
168
|
+
rspec-support (~> 3.13.0)
|
169
|
+
rspec-mocks (3.13.0)
|
170
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
171
|
+
rspec-support (~> 3.13.0)
|
172
|
+
rspec-support (3.13.1)
|
173
|
+
rubocop (1.63.1)
|
174
|
+
json (~> 2.3)
|
175
|
+
language_server-protocol (>= 3.17.0)
|
176
|
+
parallel (~> 1.10)
|
177
|
+
parser (>= 3.3.0.2)
|
178
|
+
rainbow (>= 2.2.2, < 4.0)
|
179
|
+
regexp_parser (>= 1.8, < 3.0)
|
180
|
+
rexml (>= 3.2.5, < 4.0)
|
181
|
+
rubocop-ast (>= 1.31.1, < 2.0)
|
182
|
+
ruby-progressbar (~> 1.7)
|
183
|
+
unicode-display_width (>= 2.4.0, < 3.0)
|
184
|
+
rubocop-ast (1.31.2)
|
185
|
+
parser (>= 3.3.0.4)
|
186
|
+
rubocop-capybara (2.20.0)
|
187
|
+
rubocop (~> 1.41)
|
188
|
+
rubocop-factory_bot (2.25.1)
|
189
|
+
rubocop (~> 1.41)
|
190
|
+
rubocop-inhouse (0.1.5)
|
191
|
+
rubocop (>= 1.5)
|
192
|
+
rubocop-capybara (>= 2.1)
|
193
|
+
rubocop-performance (>= 1.1)
|
194
|
+
rubocop-rails (>= 2.2)
|
195
|
+
rubocop-rake (>= 0.6)
|
196
|
+
rubocop-rspec (>= 2.2)
|
197
|
+
rubocop-performance (1.21.0)
|
198
|
+
rubocop (>= 1.48.1, < 2.0)
|
199
|
+
rubocop-ast (>= 1.31.1, < 2.0)
|
200
|
+
rubocop-rails (2.24.1)
|
201
|
+
activesupport (>= 4.2.0)
|
202
|
+
rack (>= 1.1)
|
203
|
+
rubocop (>= 1.33.0, < 2.0)
|
204
|
+
rubocop-ast (>= 1.31.1, < 2.0)
|
205
|
+
rubocop-rake (0.6.0)
|
206
|
+
rubocop (~> 1.0)
|
207
|
+
rubocop-rspec (2.29.1)
|
208
|
+
rubocop (~> 1.40)
|
209
|
+
rubocop-capybara (~> 2.17)
|
210
|
+
rubocop-factory_bot (~> 2.22)
|
211
|
+
rubocop-rspec_rails (~> 2.28)
|
212
|
+
rubocop-rspec_rails (2.28.3)
|
213
|
+
rubocop (~> 1.40)
|
214
|
+
ruby-progressbar (1.13.0)
|
215
|
+
stringio (3.1.0)
|
216
|
+
tailwind_merge (0.11.0)
|
217
|
+
lru_redux (~> 1.1)
|
218
|
+
thor (1.3.1)
|
219
|
+
tzinfo (2.0.6)
|
220
|
+
concurrent-ruby (~> 1.0)
|
221
|
+
unicode-display_width (2.5.0)
|
222
|
+
webrick (1.8.1)
|
223
|
+
xpath (3.2.0)
|
224
|
+
nokogiri (~> 1.8)
|
225
|
+
zeitwerk (2.6.13)
|
226
|
+
|
227
|
+
PLATFORMS
|
228
|
+
aarch64-linux
|
229
|
+
arm-linux
|
230
|
+
arm64-darwin
|
231
|
+
x86-linux
|
232
|
+
x86_64-darwin
|
233
|
+
x86_64-linux
|
234
|
+
|
235
|
+
DEPENDENCIES
|
236
|
+
activemodel
|
237
|
+
debug
|
238
|
+
phlex-testing-capybara
|
239
|
+
protos-protoform!
|
240
|
+
rake
|
241
|
+
rspec
|
242
|
+
rubocop-inhouse
|
243
|
+
|
244
|
+
BUNDLED WITH
|
245
|
+
2.5.6
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2023 Brad Gessler
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
# Protoform
|
2
|
+
|
3
|
+
An experimental fork of [Superform](https://github.com/rubymonolith/superform).
|
4
|
+
Uses [protos](https://github.com/inhouse-work/protos) as base components.
|
5
|
+
|
6
|
+
This is a more opinionated version of Superform. My goal is to maintain feature
|
7
|
+
parity with and contribute features back to Superform.
|
8
|
+
|
9
|
+
## Usage
|
10
|
+
|
11
|
+
```
|
12
|
+
gem "protos-protoform", require: "protoform"
|
13
|
+
```
|
14
|
+
|
15
|
+
Once the gem is installed you can run the generators:
|
16
|
+
|
17
|
+
```
|
18
|
+
bin/rails g protoform:install
|
19
|
+
```
|
20
|
+
|
21
|
+
This will:
|
22
|
+
|
23
|
+
- Add `phlex-rails` to your gemfile if it does not exist
|
24
|
+
- Add `layouts`, `components` and other folders to be autoloaded from `app/views`
|
25
|
+
- Add an `ApplicationForm` as the base form class to your `app/views`
|
26
|
+
|
27
|
+
This gem follows the same conventions as Superform with some key differences:
|
28
|
+
|
29
|
+
- Components are expected to inherit from `Protos::Component` so your
|
30
|
+
`ApplicationComponent` should inherit from that
|
31
|
+
|
32
|
+
## Development
|
33
|
+
|
34
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run
|
35
|
+
`rake spec` to run the tests. You can also run `bin/console` for an interactive
|
36
|
+
prompt that will allow you to experiment.
|
37
|
+
|
38
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To
|
39
|
+
release a new version, update the version number in `version.rb`, and then run
|
40
|
+
`bundle exec rake release`, which will create a git tag for the version, push
|
41
|
+
git commits and the created tag, and push the `.gem` file to
|
42
|
+
[rubygems.org](https://rubygems.org).
|
43
|
+
|
44
|
+
## Contributing
|
45
|
+
|
46
|
+
Bug reports and pull requests are welcome on GitHub at
|
47
|
+
https://github.com/rubymonolith/superform. This project is intended to be
|
48
|
+
a safe, welcoming space for collaboration, and contributors are expected to
|
49
|
+
adhere to the [code of
|
50
|
+
conduct](https://github.com/rubymonolith/superform/blob/main/CODE_OF_CONDUCT.md).
|
51
|
+
|
52
|
+
## License
|
53
|
+
|
54
|
+
The gem is available as open source under the terms of the
|
55
|
+
[MIT License](https://opensource.org/licenses/MIT).
|
56
|
+
|
57
|
+
## Code of Conduct
|
58
|
+
|
59
|
+
Everyone interacting in the Superform project's codebases, issue trackers, chat
|
60
|
+
rooms and mailing lists is expected to follow the
|
61
|
+
[code of conduct](https://github.com/rubymonolith/superform/blob/main/CODE_OF_CONDUCT.md).
|
data/Rakefile
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "bundler"
|
4
|
+
|
5
|
+
module Protoform
|
6
|
+
class InstallGenerator < Rails::Generators::Base
|
7
|
+
source_root File.expand_path("templates", __dir__)
|
8
|
+
|
9
|
+
APPLICATION_CONFIGURATION_PATH = Rails.root.join("config/application.rb")
|
10
|
+
|
11
|
+
def install_phlex_rails
|
12
|
+
return if gem_in_bundle? "phlex-rails"
|
13
|
+
|
14
|
+
gem "phlex-rails"
|
15
|
+
generate "phlex:install"
|
16
|
+
end
|
17
|
+
|
18
|
+
def autoload_components
|
19
|
+
return unless APPLICATION_CONFIGURATION_PATH.exist?
|
20
|
+
|
21
|
+
inject_into_class(
|
22
|
+
APPLICATION_CONFIGURATION_PATH,
|
23
|
+
"Application",
|
24
|
+
%( config.autoload_paths << "\#{root}/app/views/forms"\n)
|
25
|
+
)
|
26
|
+
end
|
27
|
+
|
28
|
+
def create_application_form
|
29
|
+
template "application_form.rb",
|
30
|
+
Rails.root.join("app/views/forms/application_form.rb")
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def gem_in_bundle?(gem_name)
|
36
|
+
Bundler.load.specs.any? { |spec| spec.name == gem_name }
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class ApplicationForm < Protoform::Rails::Form
|
4
|
+
include Phlex::Rails::Helpers::Pluralize
|
5
|
+
|
6
|
+
def row(component)
|
7
|
+
div do
|
8
|
+
render component.field.label(style: "display: block;")
|
9
|
+
render component
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def around_template(&block)
|
14
|
+
super do
|
15
|
+
error_messages
|
16
|
+
yield
|
17
|
+
submit
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def error_messages
|
22
|
+
return if model.errors.none?
|
23
|
+
|
24
|
+
div(style: "color: red;") do
|
25
|
+
h2 do
|
26
|
+
"#{pluralize model.errors.count,
|
27
|
+
"error"} prohibited this post from being saved:"
|
28
|
+
end
|
29
|
+
ul do
|
30
|
+
model.errors.each do |error|
|
31
|
+
li { error.full_message }
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Protoform
|
4
|
+
# Generates DOM IDs, names, etc. for a Field, Namespace, or Node based on
|
5
|
+
# norms that were established by Rails. These can be used outsidef or Rails in
|
6
|
+
# other Ruby web frameworks since it has now dependencies on Rails.
|
7
|
+
class DOM
|
8
|
+
def initialize(field:)
|
9
|
+
@field = field
|
10
|
+
end
|
11
|
+
|
12
|
+
# Converts the value of the field to a String, which is required to work
|
13
|
+
# with Phlex. Assumes that `Object#to_s` emits a format suitable for the web
|
14
|
+
# form.
|
15
|
+
def value
|
16
|
+
@field.value.to_s
|
17
|
+
end
|
18
|
+
|
19
|
+
# Walks from the current node to the parent node, grabs the names, and
|
20
|
+
# seperates them with a `_` for a DOM ID. One limitation of this approach is
|
21
|
+
# if multiple forms exist on the same page, the ID may be duplicate.
|
22
|
+
def id
|
23
|
+
lineage.map(&:key).join("_")
|
24
|
+
end
|
25
|
+
|
26
|
+
# The `name` attribute of a node, which is influenced by Rails (not sure
|
27
|
+
# where Rails got it from). All node names, except the parent node, are
|
28
|
+
# wrapped in a `[]` and collections are left empty. For example,
|
29
|
+
# `user[addresses][][street]` would be created for a form with data shaped
|
30
|
+
# like `{user: {addresses: [{street: "Sesame Street"}]}}`.
|
31
|
+
def name
|
32
|
+
root, *names = keys
|
33
|
+
names
|
34
|
+
.map { |name| "[#{name}]" }
|
35
|
+
.unshift(root)
|
36
|
+
.join
|
37
|
+
end
|
38
|
+
|
39
|
+
# Emit the id, name, and value in an HTML tag-ish that doesnt have an
|
40
|
+
# element.
|
41
|
+
def inspect
|
42
|
+
"<id=#{id.inspect} name=#{name.inspect} value=#{value.inspect}/>"
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def keys
|
48
|
+
lineage.map do |node|
|
49
|
+
# If the parent of a field is a field, the name should be nil.
|
50
|
+
node.key unless node.parent.is_a? Field
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
# One-liner way of walking from the current node all the way up to the
|
55
|
+
# parent.
|
56
|
+
def lineage
|
57
|
+
Enumerator.produce(@field, &:parent).take_while(&:itself).reverse
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Protoform
|
4
|
+
class Field < Node
|
5
|
+
attr_reader :dom, :object
|
6
|
+
|
7
|
+
def initialize(key, parent:, object: nil, value: nil)
|
8
|
+
super(key, parent:)
|
9
|
+
@object = object
|
10
|
+
@value = value
|
11
|
+
@dom = Protoform::DOM.new(field: self)
|
12
|
+
end
|
13
|
+
|
14
|
+
def value
|
15
|
+
if @object.respond_to? @key.to_s
|
16
|
+
@object.send @key
|
17
|
+
else
|
18
|
+
@value
|
19
|
+
end
|
20
|
+
end
|
21
|
+
alias serialize value
|
22
|
+
|
23
|
+
def assign(value)
|
24
|
+
if @object.respond_to? :"#{@key}="
|
25
|
+
@object.send :"#{@key}=", value
|
26
|
+
else
|
27
|
+
@value = value
|
28
|
+
end
|
29
|
+
end
|
30
|
+
alias value= assign
|
31
|
+
|
32
|
+
# Wraps a field that's an array of values with a bunch of fields
|
33
|
+
# that are indexed with the array's index.
|
34
|
+
def collection(&block)
|
35
|
+
@collection ||= FieldCollection.new(field: self, &block)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Protoform
|
4
|
+
class FieldCollection
|
5
|
+
include Enumerable
|
6
|
+
|
7
|
+
def initialize(field:, &block)
|
8
|
+
@field = field
|
9
|
+
@index = 0
|
10
|
+
each(&block) if block
|
11
|
+
end
|
12
|
+
|
13
|
+
def each
|
14
|
+
Enumerator.new do |collection|
|
15
|
+
values.each do |value|
|
16
|
+
collection.yield build_field(value:)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def field
|
22
|
+
build_field
|
23
|
+
end
|
24
|
+
|
25
|
+
def values
|
26
|
+
Array(@field.value)
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def build_field(**kwargs)
|
32
|
+
@field.class.new(current_index, parent: @field, **kwargs)
|
33
|
+
end
|
34
|
+
|
35
|
+
def current_index
|
36
|
+
@index += 1
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|