script_core 0.0.4 → 0.0.5

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.
Files changed (219) hide show
  1. checksums.yaml +4 -4
  2. data/.gitattributes +1 -1
  3. data/.gitignore +15 -1
  4. data/.rubocop.yml +10 -2
  5. data/.ruby-version +1 -1
  6. data/.travis.yml +6 -0
  7. data/Gemfile +32 -0
  8. data/README.md +169 -6
  9. data/Rakefile +11 -0
  10. data/Vagrantfile +1 -1
  11. data/bin/rails +25 -0
  12. data/bootstrap.sh +2 -3
  13. data/dev.yml +4 -4
  14. data/ext/enterprise_script_service/Rakefile +5 -4
  15. data/ext/enterprise_script_service/mruby_config.rb +1 -0
  16. data/lib/script_core.rb +17 -15
  17. data/lib/script_core/engine.rb +1 -0
  18. data/lib/script_core/executable.rb +1 -1
  19. data/lib/script_core/railtie.rb +8 -0
  20. data/lib/script_core/spawner.rb +1 -0
  21. data/lib/script_core/version.rb +1 -1
  22. data/lib/tasks/mruby/engine.gembox.example +19 -0
  23. data/lib/tasks/mruby/lib/.keep +0 -0
  24. data/lib/tasks/script_core.rake +111 -0
  25. data/script/regression +7 -5
  26. data/script_core.gemspec +2 -2
  27. data/spec/dummy/Rakefile +8 -0
  28. data/spec/dummy/app/assets/config/manifest.js +3 -0
  29. data/spec/dummy/app/assets/images/.keep +0 -0
  30. data/spec/dummy/app/assets/javascripts/application.es6 +56 -0
  31. data/spec/dummy/app/assets/stylesheets/application.scss +65 -0
  32. data/spec/dummy/app/controllers/application_controller.rb +4 -0
  33. data/spec/dummy/app/controllers/concerns/.keep +0 -0
  34. data/spec/dummy/app/controllers/fields/application_controller.rb +25 -0
  35. data/spec/dummy/app/controllers/fields/options_controller.rb +26 -0
  36. data/spec/dummy/app/controllers/fields/validations_controller.rb +26 -0
  37. data/spec/dummy/app/controllers/forms/application_controller.rb +14 -0
  38. data/spec/dummy/app/controllers/forms/fields_controller.rb +56 -0
  39. data/spec/dummy/app/controllers/forms/formulas/application_controller.rb +19 -0
  40. data/spec/dummy/app/controllers/forms/formulas/playgrounds_controller.rb +29 -0
  41. data/spec/dummy/app/controllers/forms/formulas_controller.rb +56 -0
  42. data/spec/dummy/app/controllers/forms_controller.rb +58 -0
  43. data/spec/dummy/app/controllers/home_controller.rb +7 -0
  44. data/spec/dummy/app/controllers/nested_forms/application_controller.rb +12 -0
  45. data/spec/dummy/app/controllers/nested_forms/fields_controller.rb +50 -0
  46. data/spec/dummy/app/controllers/playgrounds_controller.rb +29 -0
  47. data/spec/dummy/app/decorators/.keep +0 -0
  48. data/spec/dummy/app/helpers/application_helper.rb +21 -0
  49. data/spec/dummy/app/helpers/fields_helper.rb +32 -0
  50. data/spec/dummy/app/helpers/forms_helper.rb +14 -0
  51. data/spec/dummy/app/jobs/application_job.rb +4 -0
  52. data/spec/dummy/app/lib/script_engine.rb +22 -0
  53. data/spec/dummy/app/models/application_record.rb +8 -0
  54. data/spec/dummy/app/models/concerns/.keep +0 -0
  55. data/spec/dummy/app/models/concerns/acts_as_default_value.rb +152 -0
  56. data/spec/dummy/app/models/concerns/enum_attribute_localizable.rb +32 -0
  57. data/spec/dummy/app/models/concerns/fields/validations/acceptance.rb +18 -0
  58. data/spec/dummy/app/models/concerns/fields/validations/confirmation.rb +18 -0
  59. data/spec/dummy/app/models/concerns/fields/validations/exclusion.rb +35 -0
  60. data/spec/dummy/app/models/concerns/fields/validations/format.rb +45 -0
  61. data/spec/dummy/app/models/concerns/fields/validations/inclusion.rb +35 -0
  62. data/spec/dummy/app/models/concerns/fields/validations/length.rb +59 -0
  63. data/spec/dummy/app/models/concerns/fields/validations/numericality.rb +56 -0
  64. data/spec/dummy/app/models/concerns/fields/validations/presence.rb +18 -0
  65. data/spec/dummy/app/models/concerns/form_core/acts_as_default_value.rb +143 -0
  66. data/spec/dummy/app/models/field.rb +67 -0
  67. data/spec/dummy/app/models/field_options.rb +90 -0
  68. data/spec/dummy/app/models/fields.rb +10 -0
  69. data/spec/dummy/app/models/fields/boolean_field.rb +12 -0
  70. data/spec/dummy/app/models/fields/decimal_field.rb +12 -0
  71. data/spec/dummy/app/models/fields/integer_field.rb +20 -0
  72. data/spec/dummy/app/models/fields/multiple_nested_form_field.rb +35 -0
  73. data/spec/dummy/app/models/fields/nested_form_field.rb +37 -0
  74. data/spec/dummy/app/models/fields/options/boolean_field.rb +6 -0
  75. data/spec/dummy/app/models/fields/options/decimal_field.rb +12 -0
  76. data/spec/dummy/app/models/fields/options/integer_field.rb +13 -0
  77. data/spec/dummy/app/models/fields/options/multiple_nested_form_field.rb +6 -0
  78. data/spec/dummy/app/models/fields/options/nested_form_field.rb +6 -0
  79. data/spec/dummy/app/models/fields/options/text_field.rb +7 -0
  80. data/spec/dummy/app/models/fields/text_field.rb +12 -0
  81. data/spec/dummy/app/models/fields/validations/boolean_field.rb +7 -0
  82. data/spec/dummy/app/models/fields/validations/decimal_field.rb +8 -0
  83. data/spec/dummy/app/models/fields/validations/integer_field.rb +8 -0
  84. data/spec/dummy/app/models/fields/validations/multiple_nested_form_field.rb +8 -0
  85. data/spec/dummy/app/models/fields/validations/nested_form_field.rb +7 -0
  86. data/spec/dummy/app/models/fields/validations/text_field.rb +9 -0
  87. data/spec/dummy/app/models/form.rb +8 -0
  88. data/spec/dummy/app/models/formula.rb +8 -0
  89. data/spec/dummy/app/models/metal_form.rb +9 -0
  90. data/spec/dummy/app/models/nested_form.rb +5 -0
  91. data/spec/dummy/app/models/virtual_model.rb +23 -0
  92. data/spec/dummy/app/presenters/application_presenter.rb +11 -0
  93. data/spec/dummy/app/presenters/concerns/fields/presenter_for_number_field.rb +36 -0
  94. data/spec/dummy/app/presenters/fields/boolean_field_presenter.rb +13 -0
  95. data/spec/dummy/app/presenters/fields/composite_field_presenter.rb +13 -0
  96. data/spec/dummy/app/presenters/fields/decimal_field_presenter.rb +7 -0
  97. data/spec/dummy/app/presenters/fields/field_presenter.rb +44 -0
  98. data/spec/dummy/app/presenters/fields/integer_field_presenter.rb +11 -0
  99. data/spec/dummy/app/presenters/fields/multiple_nested_form_field_presenter.rb +9 -0
  100. data/spec/dummy/app/presenters/fields/nested_form_field_presenter.rb +9 -0
  101. data/spec/dummy/app/presenters/fields/text_field_presenter.rb +10 -0
  102. data/spec/dummy/app/views/_form_core/field_options/_decimal_field.html.erb +9 -0
  103. data/spec/dummy/app/views/_form_core/field_options/_integer_field.html.erb +10 -0
  104. data/spec/dummy/app/views/_form_core/field_options/_text_field.html.erb +12 -0
  105. data/spec/dummy/app/views/_form_core/fields/_boolean_field.html.erb +11 -0
  106. data/spec/dummy/app/views/_form_core/fields/_decimal_field.html.erb +9 -0
  107. data/spec/dummy/app/views/_form_core/fields/_integer_field.html.erb +9 -0
  108. data/spec/dummy/app/views/_form_core/fields/_multiple_nested_form_field.html.erb +23 -0
  109. data/spec/dummy/app/views/_form_core/fields/_nested_form.html.erb +37 -0
  110. data/spec/dummy/app/views/_form_core/fields/_nested_form_field.html.erb +42 -0
  111. data/spec/dummy/app/views/_form_core/fields/_text_field.html.erb +13 -0
  112. data/spec/dummy/app/views/_form_core/preview/_form.html.erb +17 -0
  113. data/spec/dummy/app/views/_form_core/preview/_nested_form.html.erb +22 -0
  114. data/spec/dummy/app/views/_form_core/render/_form.html.erb +39 -0
  115. data/spec/dummy/app/views/_form_core/validations/_acceptance.html.erb +12 -0
  116. data/spec/dummy/app/views/_form_core/validations/_confirmation.html.erb +12 -0
  117. data/spec/dummy/app/views/_form_core/validations/_exclusion.html.erb +2 -0
  118. data/spec/dummy/app/views/_form_core/validations/_format.html.erb +37 -0
  119. data/spec/dummy/app/views/_form_core/validations/_inclusion.html.erb +2 -0
  120. data/spec/dummy/app/views/_form_core/validations/_length.html.erb +44 -0
  121. data/spec/dummy/app/views/_form_core/validations/_numericality.html.erb +45 -0
  122. data/spec/dummy/app/views/_form_core/validations/_presence.html.erb +12 -0
  123. data/spec/dummy/app/views/fields/options/_form.html.erb +29 -0
  124. data/spec/dummy/app/views/fields/options/edit.html.erb +6 -0
  125. data/spec/dummy/app/views/fields/validations/_form.html.erb +34 -0
  126. data/spec/dummy/app/views/fields/validations/edit.html.erb +6 -0
  127. data/spec/dummy/app/views/forms/_form.html.erb +41 -0
  128. data/spec/dummy/app/views/forms/edit.html.erb +6 -0
  129. data/spec/dummy/app/views/forms/fields/_form.html.erb +71 -0
  130. data/spec/dummy/app/views/forms/fields/edit.html.erb +6 -0
  131. data/spec/dummy/app/views/forms/fields/index.html.erb +42 -0
  132. data/spec/dummy/app/views/forms/fields/new.html.erb +6 -0
  133. data/spec/dummy/app/views/forms/formulas/_form.html.erb +41 -0
  134. data/spec/dummy/app/views/forms/formulas/edit.html.erb +6 -0
  135. data/spec/dummy/app/views/forms/formulas/index.html.erb +28 -0
  136. data/spec/dummy/app/views/forms/formulas/new.html.erb +6 -0
  137. data/spec/dummy/app/views/forms/formulas/playgrounds/create.html.erb +48 -0
  138. data/spec/dummy/app/views/forms/formulas/playgrounds/show.html.erb +14 -0
  139. data/spec/dummy/app/views/forms/index.html.erb +31 -0
  140. data/spec/dummy/app/views/forms/new.html.erb +6 -0
  141. data/spec/dummy/app/views/home/index.html.erb +5 -0
  142. data/spec/dummy/app/views/layouts/_alert.html.erb +4 -0
  143. data/spec/dummy/app/views/layouts/_footer.html.erb +13 -0
  144. data/spec/dummy/app/views/layouts/_nav.html.erb +11 -0
  145. data/spec/dummy/app/views/layouts/_notice.html.erb +4 -0
  146. data/spec/dummy/app/views/layouts/application.html.erb +25 -0
  147. data/spec/dummy/app/views/layouts/forms.html.erb +33 -0
  148. data/spec/dummy/app/views/nested_forms/fields/_form.html.erb +68 -0
  149. data/spec/dummy/app/views/nested_forms/fields/edit.html.erb +6 -0
  150. data/spec/dummy/app/views/nested_forms/fields/index.html.erb +39 -0
  151. data/spec/dummy/app/views/nested_forms/fields/new.html.erb +6 -0
  152. data/spec/dummy/app/views/playgrounds/_form.html.erb +13 -0
  153. data/spec/dummy/app/views/playgrounds/create.html.erb +51 -0
  154. data/spec/dummy/app/views/playgrounds/show.html.erb +7 -0
  155. data/spec/dummy/bin/bundle +5 -0
  156. data/spec/dummy/bin/rails +6 -0
  157. data/spec/dummy/bin/rake +6 -0
  158. data/spec/dummy/bin/setup +40 -0
  159. data/spec/dummy/bin/update +35 -0
  160. data/spec/dummy/bin/yarn +13 -0
  161. data/spec/dummy/config.ru +7 -0
  162. data/spec/dummy/config/application.rb +35 -0
  163. data/spec/dummy/config/boot.rb +7 -0
  164. data/spec/dummy/config/database.yml +25 -0
  165. data/spec/dummy/config/environment.rb +7 -0
  166. data/spec/dummy/config/environments/development.rb +58 -0
  167. data/spec/dummy/config/environments/production.rb +85 -0
  168. data/spec/dummy/config/environments/test.rb +41 -0
  169. data/spec/dummy/config/initializers/application_controller_renderer.rb +10 -0
  170. data/spec/dummy/config/initializers/assets.rb +16 -0
  171. data/spec/dummy/config/initializers/backtrace_silencers.rb +9 -0
  172. data/spec/dummy/config/initializers/content_security_policy.rb +27 -0
  173. data/spec/dummy/config/initializers/cookies_serializer.rb +7 -0
  174. data/spec/dummy/config/initializers/filter_parameter_logging.rb +6 -0
  175. data/spec/dummy/config/initializers/form_core.rb +4 -0
  176. data/spec/dummy/config/initializers/inflections.rb +18 -0
  177. data/spec/dummy/config/initializers/mime_types.rb +6 -0
  178. data/spec/dummy/config/initializers/wrap_parameters.rb +16 -0
  179. data/spec/dummy/config/locales/en.yml +33 -0
  180. data/spec/dummy/config/puma.rb +36 -0
  181. data/spec/dummy/config/routes.rb +31 -0
  182. data/spec/dummy/config/spring.rb +8 -0
  183. data/spec/dummy/config/storage.yml +34 -0
  184. data/spec/dummy/db/migrate/20180916202025_create_forms.form_core.rb +12 -0
  185. data/spec/dummy/db/migrate/20180916202026_add_columns_to_forms.rb +10 -0
  186. data/spec/dummy/db/migrate/20180916202027_add_attachable_to_forms.rb +9 -0
  187. data/spec/dummy/db/migrate/20180916202030_create_fields.form_core.rb +17 -0
  188. data/spec/dummy/db/migrate/20180916202121_add_columns_to_fields.rb +10 -0
  189. data/spec/dummy/db/migrate/20180916202124_add_position_to_fields.rb +9 -0
  190. data/spec/dummy/db/migrate/20181111111412_create_formulas.rb +13 -0
  191. data/spec/dummy/db/schema.rb +52 -0
  192. data/spec/dummy/lib/assets/.keep +0 -0
  193. data/spec/dummy/lib/monkey_patches/active_support.rb +3 -0
  194. data/spec/dummy/lib/monkey_patches/active_support/concern+prependable.rb +28 -0
  195. data/spec/dummy/lib/monkey_patches/big_decimal.rb +8 -0
  196. data/spec/dummy/log/.keep +0 -0
  197. data/spec/dummy/mruby/engine.gembox +19 -0
  198. data/spec/dummy/mruby/lib/.keep +0 -0
  199. data/spec/dummy/mruby/lib/core_ext.rb +62 -0
  200. data/spec/dummy/mruby/lib/harden.rb +1 -0
  201. data/spec/dummy/mruby/lib/input.rb +20 -0
  202. data/spec/dummy/mruby/lib/io.rb +19 -0
  203. data/spec/dummy/mruby/lib/output.rb +35 -0
  204. data/spec/dummy/mruby/lib/script_kernel.rb +12 -0
  205. data/spec/dummy/package.json +5 -0
  206. data/spec/dummy/public/404.html +67 -0
  207. data/spec/dummy/public/422.html +67 -0
  208. data/spec/dummy/public/500.html +66 -0
  209. data/spec/dummy/public/apple-touch-icon-precomposed.png +0 -0
  210. data/spec/dummy/public/apple-touch-icon.png +0 -0
  211. data/spec/dummy/public/favicon.ico +0 -0
  212. data/spec/dummy/storage/.keep +0 -0
  213. data/spec/dummy/test/controllers/.keep +0 -0
  214. data/spec/dummy/test/fixtures/.keep +0 -0
  215. data/spec/dummy/test/models/.keep +0 -0
  216. data/spec/script_core_spec.rb +2 -2
  217. data/spec/spec_helper.rb +2 -2
  218. metadata +199 -5
  219. data/circle.yml +0 -9
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Concerns::Fields
4
+ module Validations::Numericality
5
+ extend ActiveSupport::Concern
6
+
7
+ included do
8
+ embeds_one :numericality, class_name: "Concerns::Fields::Validations::Numericality::NumericalityOptions"
9
+ accepts_nested_attributes_for :numericality
10
+
11
+ after_initialize do
12
+ build_numericality unless numericality
13
+ end
14
+ end
15
+
16
+ def interpret_to(model, field_name, accessibility, options = {})
17
+ super
18
+ numericality&.interpret_to model, field_name, accessibility, options
19
+ end
20
+
21
+ class NumericalityOptions < FieldOptions
22
+ attribute :lower_bound_check, :string, default: "disabled"
23
+ attribute :upper_bound_check, :string, default: "disabled"
24
+
25
+ attribute :lower_bound_value, :float, default: 0.0
26
+ attribute :upper_bound_value, :float, default: 0.0
27
+
28
+ enum lower_bound_check: {
29
+ disabled: "disabled",
30
+ greater_than: "greater_than",
31
+ greater_than_or_equal_to: "greater_than_or_equal_to"
32
+ }, _prefix: :lower_bound_check
33
+ enum upper_bound_check: {
34
+ disabled: "disabled",
35
+ less_than: "less_than",
36
+ less_than_or_equal_to: "less_than_or_equal_to"
37
+ }, _prefix: :upper_bound_check
38
+
39
+ validates :upper_bound_value,
40
+ numericality: {
41
+ greater_than: :lower_bound_value
42
+ },
43
+ if: proc { upper_bound_check != "disabled" && lower_bound_check != "disabled" }
44
+
45
+ def interpret_to(model, field_name, _accessibility, _options = {})
46
+ options = {}
47
+ options[lower_bound_check] = lower_bound_value unless lower_bound_check_disabled?
48
+ options[upper_bound_check] = upper_bound_value unless upper_bound_check_disabled?
49
+ return if options.empty?
50
+
51
+ options.symbolize_keys!
52
+ model.validates field_name, numericality: options, allow_blank: true
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Concerns::Fields
4
+ module Validations::Presence
5
+ extend ActiveSupport::Concern
6
+
7
+ included do
8
+ attribute :presence, :boolean, default: false
9
+ end
10
+
11
+ def interpret_to(model, field_name, _accessibility, _options = {})
12
+ super
13
+ return unless presence
14
+
15
+ model.validates field_name, presence: true
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,143 @@
1
+ # frozen_string_literal: true
2
+
3
+ # https://github.com/FooBarWidget/default_value_for
4
+ #
5
+ # Copyright (c) 2008-2012 Phusion
6
+ #
7
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
8
+ # of this software and associated documentation files (the "Software"), to deal
9
+ # in the Software without restriction, including without limitation the rights
10
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
+ # copies of the Software, and to permit persons to whom the Software is
12
+ # furnished to do so, subject to the following conditions:
13
+ #
14
+ # The above copyright notice and this permission notice shall be included in
15
+ # all copies or substantial portions of the Software.
16
+ #
17
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23
+ # THE SOFTWARE.
24
+
25
+ module FormCore
26
+ module ActsAsDefaultValue
27
+ extend ActiveSupport::Concern
28
+
29
+ class NormalValueContainer
30
+ def initialize(value)
31
+ @value = value
32
+ end
33
+
34
+ def evaluate(_instance)
35
+ if @value.duplicable?
36
+ @value.dup
37
+ else
38
+ @value
39
+ end
40
+ end
41
+ end
42
+
43
+ class BlockValueContainer
44
+ def initialize(block)
45
+ @block = block
46
+ end
47
+
48
+ def evaluate(instance)
49
+ if @block.arity == 0
50
+ @block.call
51
+ else
52
+ @block.call(instance)
53
+ end
54
+ end
55
+ end
56
+
57
+ included do
58
+ after_initialize :set_default_values
59
+ end
60
+
61
+ def initialize(attributes = nil)
62
+ @initialization_attributes = attributes.is_a?(Hash) ? attributes.stringify_keys : {}
63
+ super
64
+ end
65
+
66
+ def set_default_values
67
+ self.class._all_default_attribute_values.each do |attribute, container|
68
+ next unless new_record? || self.class._all_default_attribute_values_not_allowing_nil.include?(attribute)
69
+
70
+ attribute_blank =
71
+ if self.class.attribute_types[attribute]&.type == :boolean
72
+ send(attribute).nil?
73
+ else
74
+ send(attribute).blank?
75
+ end
76
+ next unless attribute_blank
77
+
78
+ # allow explicitly setting nil through allow nil option
79
+ next if @initialization_attributes.is_a?(Hash) &&
80
+ (
81
+ @initialization_attributes.key?(attribute) ||
82
+ (
83
+ @initialization_attributes.key?("#{attribute}_attributes") &&
84
+ nested_attributes_options.stringify_keys[attribute]
85
+ )
86
+ ) &&
87
+ !self.class._all_default_attribute_values_not_allowing_nil.include?(attribute)
88
+
89
+ send("#{attribute}=", container.evaluate(self))
90
+
91
+ clear_attribute_changes [attribute] if has_attribute?(attribute)
92
+ end
93
+ end
94
+
95
+ module ClassMethods
96
+ def _default_attribute_values # :nodoc:
97
+ @default_attribute_values ||= {}
98
+ end
99
+
100
+ def _default_attribute_values_not_allowing_nil # :nodoc:
101
+ @default_attribute_values_not_allowing_nil ||= Set.new
102
+ end
103
+
104
+ def _all_default_attribute_values # :nodoc:
105
+ if superclass.respond_to?(:_default_attribute_values)
106
+ superclass._all_default_attribute_values.merge(_default_attribute_values)
107
+ else
108
+ _default_attribute_values
109
+ end
110
+ end
111
+
112
+ def _all_default_attribute_values_not_allowing_nil # :nodoc:
113
+ if superclass.respond_to?(:_default_attribute_values_not_allowing_nil)
114
+ superclass._all_default_attribute_values_not_allowing_nil + _default_attribute_values_not_allowing_nil
115
+ else
116
+ _default_attribute_values_not_allowing_nil
117
+ end
118
+ end
119
+
120
+ # Declares a default value for the given attribute.
121
+ #
122
+ # Sets the default value to the given options parameter
123
+ #
124
+ # The <tt>options</tt> can be used to specify the following things:
125
+ # * <tt>allow_nil (default: true)</tt> - Sets explicitly passed nil values if option is set to true.
126
+ def default_value_for(attribute, value, **options)
127
+ allow_nil = options.fetch(:allow_nil, true)
128
+
129
+ container =
130
+ if value.is_a? Proc
131
+ BlockValueContainer.new(value)
132
+ else
133
+ NormalValueContainer.new(value)
134
+ end
135
+
136
+ _default_attribute_values[attribute.to_s] = container
137
+ _default_attribute_values_not_allowing_nil << attribute.to_s unless allow_nil
138
+
139
+ attribute
140
+ end
141
+ end
142
+ end
143
+ end
@@ -0,0 +1,67 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Field < ApplicationRecord
4
+ include FormCore::Concerns::Models::Field
5
+
6
+ self.table_name = "fields"
7
+
8
+ belongs_to :form, class_name: "MetalForm", foreign_key: "form_id", touch: true
9
+
10
+ validates :label,
11
+ presence: true
12
+ validates :type,
13
+ inclusion: {
14
+ in: ->(_) { Field.descendants.map(&:to_s) }
15
+ },
16
+ allow_blank: false
17
+
18
+ default_value_for :name,
19
+ ->(_) { "field_#{SecureRandom.hex(3)}" },
20
+ allow_nil: false
21
+
22
+ def self.type_key
23
+ model_name.name.split("::").last.underscore
24
+ end
25
+
26
+ def type_key
27
+ self.class.type_key
28
+ end
29
+
30
+ def options_configurable?
31
+ options.is_a?(FieldOptions) && options.attributes.any?
32
+ end
33
+
34
+ def validations_configurable?
35
+ validations.is_a?(FieldOptions) && validations.attributes.any?
36
+ end
37
+
38
+ protected
39
+
40
+ def interpret_validations_to(model, accessibility, overrides = {})
41
+ return unless accessibility == :read_and_write
42
+
43
+ validations_overrides = overrides.fetch(:validations) { {} }
44
+ validations =
45
+ if validations_overrides.any?
46
+ self.validations.dup.update(validations_overrides)
47
+ else
48
+ self.validations
49
+ end
50
+
51
+ validations.interpret_to(model, name, accessibility)
52
+ end
53
+
54
+ def interpret_extra_to(model, accessibility, overrides = {})
55
+ options_overrides = overrides.fetch(:options) { {} }
56
+ options =
57
+ if options_overrides.any?
58
+ self.options.dup.update(options_overrides)
59
+ else
60
+ self.options
61
+ end
62
+
63
+ options.interpret_to(model, name, accessibility)
64
+ end
65
+ end
66
+
67
+ require_dependency "fields"
@@ -0,0 +1,90 @@
1
+ # frozen_string_literal: true
2
+
3
+ class FieldOptions < DuckRecord::Base
4
+ include FormCore::ActsAsDefaultValue
5
+ include EnumAttributeLocalizable
6
+
7
+ class_attribute :keeping_old_serialization
8
+
9
+ attr_accessor :raw_attributes
10
+
11
+ def interpret_to(_model, _field_name, _accessibility, _options = {}); end
12
+
13
+ def serializable_hash(options = {})
14
+ options = (options || {}).reverse_merge include: self.class._embeds_reflections.keys
15
+ super options
16
+ end
17
+
18
+ private
19
+
20
+ def _assign_attribute(k, v)
21
+ return unless respond_to?("#{k}=")
22
+
23
+ public_send("#{k}=", v)
24
+ end
25
+
26
+ class << self
27
+ def _embeds_reflections
28
+ _reflections.select { |_, v| v.is_a? DuckRecord::Reflection::EmbedsAssociationReflection }
29
+ end
30
+
31
+ def model_version
32
+ 1
33
+ end
34
+
35
+ def root_key_for_serialization
36
+ "#{self}.#{model_version}"
37
+ end
38
+
39
+ def dump(obj)
40
+ return YAML.dump({}) unless obj
41
+
42
+ serializable_hash =
43
+ if obj.respond_to?(:serializable_hash)
44
+ obj.serializable_hash
45
+ elsif obj.respond_to?(:to_hash)
46
+ obj.to_hash
47
+ else
48
+ raise ArgumentError, "`obj` required can be cast to `Hash` -- #{obj.class}"
49
+ end.stringify_keys
50
+
51
+ data = {root_key_for_serialization => serializable_hash}
52
+ data.reverse_merge! obj.raw_attributes if keeping_old_serialization
53
+
54
+ YAML.dump(data)
55
+ end
56
+
57
+ def load(yaml_or_hash)
58
+ case yaml_or_hash
59
+ when Hash
60
+ load_from_hash(yaml_or_hash)
61
+ when String
62
+ load_from_yaml(yaml_or_hash)
63
+ else
64
+ new
65
+ end
66
+ end
67
+
68
+ WHITELIST_CLASSES = [BigDecimal, Date, Time, Symbol].freeze
69
+ def load_from_yaml(yaml)
70
+ return new if yaml.blank?
71
+
72
+ return new unless yaml.is_a?(String) && /^---/.match?(yaml)
73
+
74
+ decoded = YAML.safe_load(yaml, WHITELIST_CLASSES)
75
+ return new unless decoded.is_a? Hash
76
+
77
+ record = new decoded[root_key_for_serialization]
78
+ record.raw_attributes = decoded.freeze
79
+ record
80
+ end
81
+
82
+ def load_from_hash(hash)
83
+ return new if hash.blank?
84
+
85
+ record = new hash[root_key_for_serialization]
86
+ record.raw_attributes = hash.freeze
87
+ record
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Fields
4
+ %w[
5
+ text boolean decimal integer
6
+ nested_form multiple_nested_form
7
+ ].each do |type|
8
+ require_dependency "fields/#{type}_field"
9
+ end
10
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Fields
4
+ class BooleanField < Field
5
+ serialize :validations, Validations::BooleanField
6
+ serialize :options, Options::BooleanField
7
+
8
+ def stored_type
9
+ :boolean
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Fields
4
+ class DecimalField < Field
5
+ serialize :validations, Validations::DecimalField
6
+ serialize :options, Options::DecimalField
7
+
8
+ def stored_type
9
+ :decimal
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Fields
4
+ class IntegerField < Field
5
+ serialize :validations, Validations::IntegerField
6
+ serialize :options, Options::IntegerField
7
+
8
+ def stored_type
9
+ :integer
10
+ end
11
+
12
+ protected
13
+
14
+ def interpret_extra_to(model, accessibility, _overrides = {})
15
+ return if accessibility != :read_and_write
16
+
17
+ model.validates name, numericality: {only_integer: true}, allow_blank: true
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Fields
4
+ class MultipleNestedFormField < Field
5
+ has_one :nested_form, as: :attachable, dependent: :destroy
6
+
7
+ after_create do
8
+ build_nested_form.save!
9
+ end
10
+
11
+ serialize :validations, Validations::MultipleNestedFormField
12
+ serialize :options, Options::MultipleNestedFormField
13
+
14
+ def interpret_to(model, overrides: {})
15
+ check_model_validity!(model)
16
+
17
+ accessibility = overrides.fetch(:accessibility, self.accessibility)
18
+ return model if accessibility == :hidden
19
+
20
+ overrides[:name] = name
21
+
22
+ nested_model = nested_form.to_virtual_model(overrides: {_global: {accessibility: accessibility}})
23
+
24
+ model.nested_models[name] = nested_model
25
+
26
+ model.embeds_many name, anonymous_class: nested_model, validate: true
27
+ model.accepts_nested_attributes_for name, reject_if: :all_blank
28
+
29
+ interpret_validations_to model, accessibility, overrides
30
+ interpret_extra_to model, accessibility, overrides
31
+
32
+ model
33
+ end
34
+ end
35
+ end