formula 1.1.1 → 2.0.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
- SHA1:
3
- metadata.gz: b3c844a3b82fc2394cc192c4eaaf04990a6b21a7
4
- data.tar.gz: 4539895dac54e7330b3c5f2c429499fabb1b11f5
2
+ SHA256:
3
+ metadata.gz: 8e753004d2065d2a0aa15c73ac8393b54de9ae40086f2f5da874e0cd1a0ccd8a
4
+ data.tar.gz: 21797db2580b4ae567942e4b3c36e2c86caed7645d58ecd4ba10cecb25449ad5
5
5
  SHA512:
6
- metadata.gz: e6e13d92a4e16f4aebdfd1925edd425223404984fd2fb721454011b72d331a2080684eafb619781afc803d13c48d4cff34aa5ff31f360792ae95587d26a64f86
7
- data.tar.gz: c4cb45eb4a68624974886b3c62c16209e89f6447a20e5d5daef21ef904a82b98e8271bd52207be19486f4019bb8c4afa26c410efe810fbf76e144d34d700d1d2
6
+ metadata.gz: 59d014229aa1940f2b0d08b263d6bc49ab9caa836b4e4b993bc3c9407b2544fd789e8a36f1e324a19f467d8895b23ab3d15fa14fd3af27c77b426abe25c908b4
7
+ data.tar.gz: cd47a5b0382b1bf898a2e0691c3234504e016ab29d96496290127903ae3bafe6140cedd651e554f3f2a626ecf43293d1cb4fc318ef833e236417cca9bd11b522
data/Gemfile ADDED
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
4
+
5
+ gemspec
6
+
7
+ gem 'bcrypt'
8
+ gem 'puma'
9
+ gem 'rubocop'
10
+ gem 'sqlite3'
11
+ gem 'yard'
data/README.md ADDED
@@ -0,0 +1,71 @@
1
+ # Formula
2
+
3
+ Formula is a Rails form helper that generates awesome markup. The project lets users create semantically beautiful forms without introducing too much syntax.
4
+
5
+ ## Requirements
6
+
7
+ The gem is tested with:
8
+
9
+ - Ruby 3.3
10
+ - Rails 7.2
11
+
12
+ ## Installation
13
+
14
+ ```bash
15
+ gem install formula
16
+ ```
17
+
18
+ ## Examples
19
+
20
+ ```erb
21
+ <%= formula_form_for @user do |f| %>
22
+ <%= f.input :email %>
23
+ <%= f.input :password %>
24
+ <%= f.button 'Save' %>
25
+ <% end %>
26
+ ```
27
+
28
+ ```erb
29
+ <%= formula_form_for @user do |f| %>
30
+ <%= f.input :email, label: "Email:", hint: "We promise never to bother you." %>
31
+ <%= f.input :password, label: "Password:", hint: "Must be at least six characters." %>
32
+ <%= f.button 'Save' %>
33
+ <% end %>
34
+ ```
35
+
36
+ ```erb
37
+ <%= formula_form_for @company do |f|
38
+ <%= f.input :url, container: { class: 'third' }, input: { class: 'fill' } %>
39
+ <%= f.input :phone, container: { class: 'third' }, input: { class: 'fill' } %>
40
+ <%= f.input :email, container: { class: 'third' }, input: { class: 'fill' } %>
41
+ <%= f.button 'Save', button: { class: 'fancy' } %>
42
+ <% end %>
43
+ ```
44
+
45
+ ```erb
46
+ <%= formula_form_for @user do |f| %>
47
+ <%= f.input :email, label: "Email:" %>
48
+ <%= f.input :password, label: "Password:" %>
49
+ <%= f.input :gender, label: 'Gender:', as: :select, choices: User::GENDERS %>
50
+ <%= formula_fields_for @user.payment do |payment_f| %>
51
+ <%= payment_f.input :credit_card_number, label: 'Number:' %>
52
+ <%= payment_f.input :credit_card_expiration, label: 'Expiration:' %>
53
+ <% end %>
54
+ <%= f.button 'Save', button: { class: 'fancy' } %>
55
+ <% end %>
56
+ ```
57
+
58
+ ```erb
59
+ <%= formula_form_for @user do |f| %>
60
+ <%= f.block :favourite %>
61
+ <% @favourites.each do |favourite| %>
62
+ ...
63
+ <% end %>
64
+ <% end %>
65
+ <%= f.button 'Save', button: { class: 'fancy' } %>
66
+ <% end %>
67
+ ```
68
+
69
+ ## Copyright
70
+
71
+ Copyright (c) 2010 - 2024 Kevin Sylvestre. See LICENSE for details.
data/bin/rubocop ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env ruby
2
+ require "rubygems"
3
+ require "bundler/setup"
4
+
5
+ # explicit rubocop config increases performance slightly while avoiding config confusion.
6
+ ARGV.unshift("--config", File.expand_path("../.rubocop.yml", __dir__))
7
+
8
+ load Gem.bin_path("rubocop", "rubocop")
data/bin/test ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+ $: << File.expand_path("../test", __dir__)
3
+
4
+ require "bundler/setup"
5
+ require "rails/plugin/test"
@@ -0,0 +1,136 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Formula
4
+ class Config
5
+ # @!attribute [rw] box_options
6
+ # @return [Hash]
7
+ attr_accessor :box_options
8
+
9
+ # @!attribute [rw] area_options
10
+ # @return [Hash]
11
+ attr_accessor :area_options
12
+
13
+ # @!attribute [rw] file_options
14
+ # @return [Hash]
15
+ attr_accessor :file_options
16
+
17
+ # @!attribute [rw] field_options
18
+ # @return [Hash]
19
+ attr_accessor :field_options
20
+
21
+ # @!attribute [rw] select_options
22
+ # @return [Hash]
23
+ attr_accessor :select_options
24
+
25
+ # @!attribute [rw] label_options
26
+ # @return [Hash]
27
+ attr_accessor :label_options
28
+
29
+ # Default class assigned to block (<div class="block">...</div>).
30
+ #
31
+ # @!attribute [rw] block_class
32
+ # @return [String]
33
+ attr_accessor :block_class
34
+
35
+ # Default class assigned to input (<div class="input">...</div>).
36
+ #
37
+ # @!attribute [rw] input_class
38
+ # @return [String]
39
+ attr_accessor :input_class
40
+
41
+ # Default class assigned to association (<div class="association">...</div>).
42
+ #
43
+ # @!attribute [rw] association_class
44
+ # @return [String]
45
+ attr_accessor :association_class
46
+
47
+ # Default class assigned to block with errors (<div class="block errors">...</div>).
48
+ #
49
+ # @!attribute [rw] block_error_class
50
+ # @return [String]
51
+ attr_accessor :block_error_class
52
+
53
+ # Default class assigned to input with errors (<div class="input errors">...</div>).
54
+ #
55
+ # @!attribute [rw] input_error_class
56
+ # @return [String]
57
+ attr_accessor :input_error_class
58
+
59
+ # Default class assigned to input with errors (<div class="association errors">...</div>).
60
+ #
61
+ # @!attribute [rw] association_error_class
62
+ # @return [String]
63
+ attr_accessor :association_error_class
64
+
65
+ # Default class assigned to error (<div class="error">...</div>).
66
+ #
67
+ # @!attribute [rw] error_class
68
+ # @return [String]
69
+ attr_accessor :error_class
70
+
71
+ # Default class assigned to hint (<div class="hint">...</div>).
72
+ #
73
+ # @!attribute [rw] hint_class
74
+ # @return [String]
75
+ attr_accessor :hint_class
76
+
77
+ # Default tag assigned to block (<div class="input">...</div>).
78
+ #
79
+ # @!attribute [rw] block_tag
80
+ # @return [Symbol]
81
+ attr_accessor :block_tag
82
+
83
+ # Default tag assigned to input (<div class="input">...</div>).
84
+ #
85
+ # @!attribute [rw] input_tag
86
+ # @return [Symbol]
87
+ attr_accessor :input_tag
88
+
89
+ # Default tag assigned to association (<div class="association">...</div>).
90
+ #
91
+ # @!attribute [rw] association_tag
92
+ # @return [Symbol]
93
+ attr_accessor :association_tag
94
+
95
+ # Default tag assigned to error (<div class="error">...</div>).
96
+ #
97
+ # @!attribute [rw] error_tag
98
+ # @return [Symbol]
99
+ attr_accessor :error_tag
100
+
101
+ # Default tag assigned to hint (<div class="hint">...</div>).
102
+ #
103
+ # @!attribute [rw] hint_tag
104
+ # @return [Symbol]
105
+ attr_accessor :hint_tag
106
+
107
+ # Default as is :string.
108
+ #
109
+ # @!attribute [rw] default_as
110
+ # @return [Symbol]
111
+ attr_accessor :default_as
112
+
113
+ def initialize
114
+ @box_options = {}
115
+ @area_options = {}
116
+ @file_options = {}
117
+ @field_options = {}
118
+ @select_options = {}
119
+ @label_options = {}
120
+ @block_class = 'block'
121
+ @input_class = 'input'
122
+ @association_class = 'association'
123
+ @block_error_class = 'errors'
124
+ @input_error_class = false
125
+ @association_error_class = false
126
+ @error_class = 'error'
127
+ @hint_class = 'hint'
128
+ @block_tag = :div
129
+ @input_tag = :div
130
+ @association_tag = :div
131
+ @error_tag = :div
132
+ @hint_tag = :div
133
+ @default_as = :string
134
+ end
135
+ end
136
+ end
@@ -0,0 +1,351 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Formula
4
+ class FormBuilder < ::ActionView::Helpers::FormBuilder
5
+ # Generate a form button.
6
+ #
7
+ # Options:
8
+ #
9
+ # * :container - add custom options to the container
10
+ # * :button - add custom options to the button
11
+ #
12
+ # Usage:
13
+ #
14
+ # f.button(:name)
15
+ #
16
+ # Equivalent:
17
+ #
18
+ # <div class="block">
19
+ # <%= f.submit("Save")
20
+ # </div>
21
+ def button(value = nil, options = {})
22
+ options[:button] ||= {}
23
+
24
+ options[:container] ||= {}
25
+ options[:container][:class] = arrayorize(options[:container][:class]) << config.block_class
26
+
27
+ @template.content_tag(config.block_tag, options[:container]) do
28
+ submit value, options[:button]
29
+ end
30
+ end
31
+
32
+ # Basic container generator for use with blocks.
33
+ #
34
+ # Options:
35
+ #
36
+ # * :hint - specify a hint to be displayed ('We promise not to spam you.', etc.)
37
+ # * :label - override the default label used ('Name:', 'URL:', etc.)
38
+ # * :error - override the default error used ('invalid', 'incorrect', etc.)
39
+ #
40
+ # Usage:
41
+ #
42
+ # f.block(:name, :label => "Name:", :hint => "Please use your full name.", :container => { :class => 'fill' }) do
43
+ # ...
44
+ # end
45
+ #
46
+ # Equivalent:
47
+ #
48
+ # <div class='block fill'>
49
+ # <%= f.label(:name, "Name:") %>
50
+ # ...
51
+ # <div class="hint">Please use your full name.</div>
52
+ # <div class="error">...</div>
53
+ # </div>
54
+ def block(method = nil, options = {}, &block)
55
+ options[:error] ||= error(method) if method
56
+
57
+ components = ''.html_safe
58
+
59
+ components << label(method, options[:label], config.label_options) if method
60
+
61
+ components << @template.capture(&block)
62
+
63
+ options[:container] ||= {}
64
+ options[:container][:class] = arrayorize(options[:container][:class]) << config.block_class << method
65
+ options[:container][:class] << config.block_error_class if config.block_error_class.present? and error?(method)
66
+
67
+ if options[:hint]
68
+ components << @template.content_tag(config.hint_tag, options[:hint],
69
+ class: config.hint_class)
70
+ end
71
+ if options[:error]
72
+ components << @template.content_tag(config.error_tag, options[:error],
73
+ class: config.error_class)
74
+ end
75
+
76
+ @template.content_tag(config.block_tag, options[:container]) do
77
+ components
78
+ end
79
+ end
80
+
81
+ # Generate a suitable form input for a given method by performing introspection on the type.
82
+ #
83
+ # Options:
84
+ #
85
+ # * :as - override the default type used (:url, :email, :phone, :password, :number, :text)
86
+ # * :label - override the default label used ('Name:', 'URL:', etc.)
87
+ # * :error - override the default error used ('invalid', 'incorrect', etc.)
88
+ # * :input - add custom options to the input ({ :class => 'goregous' }, etc.)
89
+ # * :container - add custom options to the container ({ :class => 'gorgeous' }, etc.)
90
+ #
91
+ # Usage:
92
+ #
93
+ # f.input(:name)
94
+ # f.input(:email)
95
+ # f.input(:password_a, :label => "Password", :hint => "It's a secret!", :container => { :class => "half" })
96
+ # f.input(:password_b, :label => "Password", :hint => "It's a secret!", :container => { :class => "half" })
97
+ #
98
+ # Equivalent:
99
+ #
100
+ # <div class="block name">
101
+ # <%= f.label(:name)
102
+ # <div class="input string"><%= f.text_field(:name)</div>
103
+ # <div class="error">...</div>
104
+ # </div>
105
+ # <div class="block email">
106
+ # <%= f.label(:email)
107
+ # <div class="input string"><%= f.email_field(:email)</div>
108
+ # <div class="error">...</div>
109
+ # </div>
110
+ # <div class="block half password_a">
111
+ # <div class="input">
112
+ # <%= f.label(:password_a, "Password")
113
+ # <%= f.password_field(:password_a)
114
+ # <div class="hint">It's a secret!</div>
115
+ # <div class="error">...</div>
116
+ # </div>
117
+ # </div>
118
+ # <div class="block half password_b">
119
+ # <div class="input">
120
+ # <%= f.label(:password_b, "Password")
121
+ # <%= f.password_field(:password_b)
122
+ # <div class="hint">It's a secret!</div>
123
+ # <div class="error">...</div>
124
+ # </div>
125
+ # </div>
126
+ def input(method, options = {})
127
+ options[:as] ||= as(method)
128
+ options[:input] ||= {}
129
+
130
+ return hidden_field method, options[:input] if options[:as] == :hidden
131
+
132
+ klass = [config.input_class, options[:as]]
133
+ klass << config.input_error_class if config.input_error_class.present? and error?(method)
134
+
135
+ block(method, options) do
136
+ @template.content_tag(config.input_tag, class: klass) do
137
+ case options[:as]
138
+ when :text then text_area method, config.area_options.merge(options[:input] || {})
139
+ when :file then file_field method, config.file_options.merge(options[:input] || {})
140
+ when :string then text_field method, config.field_options.merge(options[:input] || {})
141
+ when :password then password_field method, config.field_options.merge(options[:input] || {})
142
+ when :url then url_field method, config.field_options.merge(options[:input] || {})
143
+ when :email then email_field method, config.field_options.merge(options[:input] || {})
144
+ when :phone then phone_field method, config.field_options.merge(options[:input] || {})
145
+ when :number then number_field method, config.field_options.merge(options[:input] || {})
146
+ when :boolean then check_box method, config.box_options.merge(options[:input] || {})
147
+ when :country then country_select method, config.select_options.merge(options[:input] || {})
148
+ when :date then date_select method, config.select_options.merge(options[:input] || {}),
149
+ options[:input].delete(:html) || {}
150
+ when :time then time_select method, config.select_options.merge(options[:input] || {}),
151
+ options[:input].delete(:html) || {}
152
+ when :datetime then datetime_select method, config.select_options.merge(options[:input] || {}),
153
+ options[:input].delete(:html) || {}
154
+ when :select then select method, options[:choices],
155
+ config.select_options.merge(options[:input] || {}), options[:input].delete(:html) || {}
156
+ end
157
+ end
158
+ end
159
+ end
160
+
161
+ # Generate a suitable form association for a given method by performing introspection on the type.
162
+ #
163
+ # Options:
164
+ #
165
+ # * :label - override the default label used ('Name:', 'URL:', etc.)
166
+ # * :error - override the default error used ('invalid', 'incorrect', etc.)
167
+ # * :association - add custom options to the input ({ :class => 'goregous' }, etc.)
168
+ # * :container - add custom options to the container ({ :class => 'gorgeous' }, etc.)
169
+ #
170
+ # Usage:
171
+ #
172
+ # f.association(:category, Category.all, :id, :name, :hint => "What do you do?")
173
+ # f.association(:category, Category.all, :id, :name, :association => { :prompt => "Category?" })
174
+ # f.association(:category, Category.all, :id, :name, :association => { :html => { :class => "category" } })
175
+ #
176
+ # Equivalent:
177
+ #
178
+ # <div>
179
+ # <div class="association category">
180
+ # <%= f.label(:category)
181
+ # <div class="association">
182
+ # <%= f.collection_select(:category, Category.all, :id, :name) %>
183
+ # </div>
184
+ # <div class="hint">What do you do?</div>
185
+ # <div class="error">...</div>
186
+ # </div>
187
+ # </div>
188
+ # <div>
189
+ # <div class="association category">
190
+ # <%= f.label(:category)
191
+ # <div class="association">
192
+ # <%= f.collection_select(:category, Category.all, :id, :name, { :prompt => "Category") } %>
193
+ # </div>
194
+ # <div class="error">...</div>
195
+ # </div>
196
+ # </div>
197
+ # <div>
198
+ # <div class="association category">
199
+ # <%= f.label(:category)
200
+ # <div class="association">
201
+ # <%= f.collection_select(:category, Category.all, :id, :name, {}, { :class => "category" } %>
202
+ # </div>
203
+ # <div class="error">...</div>
204
+ # </div>
205
+ # </div>
206
+ def association(method, collection, value, text, options = {})
207
+ options[:as] ||= :select
208
+ options[:association] ||= {}
209
+
210
+ klass = [config.association_class, options[:as]]
211
+ klass << config.association_error_class if config.association_error_class.present? and error?(method)
212
+
213
+ block(method, options) do
214
+ @template.content_tag(config.association_tag, class: klass) do
215
+ case options[:as]
216
+ when :select then collection_select :"#{method}_id", collection, value, text,
217
+ options[:association], options[:association].delete(:html) || {}
218
+ end
219
+ end
220
+ end
221
+ end
222
+
223
+ private
224
+
225
+ def config
226
+ ::Formula.config
227
+ end
228
+
229
+ # Introspection on the column to determine how to render a method. The method is used to
230
+ # identify a method type (if the method corresponds to a column)
231
+ #
232
+ # Returns:
233
+ #
234
+ # * :text - for columns of type 'text'
235
+ # * :string - for columns of type 'string'
236
+ # * :integer - for columns of type 'integer'
237
+ # * :float - for columns of type 'float'
238
+ # * :decimal - for columns of type 'decimal'
239
+ # * :datetime - for columns of type 'datetime'
240
+ # * :date - for columns of type 'date'
241
+ # * :time - for columns of type 'time'
242
+ # * nil - for unkown columns
243
+ def type(method)
244
+ return unless @object.respond_to?(:has_attribute?) && @object.has_attribute?(method)
245
+
246
+ column = @object.column_for_attribute(method) if @object.respond_to?(:column_for_attribute)
247
+ column.type if column
248
+ end
249
+
250
+ # Introspection on an association to determine if a method is a file. This
251
+ # is determined by the methods ability to respond to file methods.
252
+ def file?(method)
253
+ @files ||= {}
254
+ @files[method] ||= begin
255
+ file = @object.send(method) if @object && @object.respond_to?(method)
256
+ file.is_a?(::ActiveStorage::Attached)
257
+ end
258
+ end
259
+
260
+ # Introspection on the field and method to determine how to render a method. The method is
261
+ # used to generate form element types.
262
+ #
263
+ # Returns:
264
+ #
265
+ # * :url - for columns containing 'url'
266
+ # * :email - for columns containing 'email'
267
+ # * :phone - for columns containing 'phone'
268
+ # * :password - for columns containing 'password'
269
+ # * :number - for integer, float or decimal columns
270
+ # * :datetime - for datetime or timestamp columns
271
+ # * :date - for date column
272
+ # * :time - for time column
273
+ # * :text - for time column
274
+ # * :string - for all other cases
275
+ def as(method)
276
+ case "#{method}"
277
+ when /url/ then return :url
278
+ when /email/ then return :email
279
+ when /phone/ then return :phone
280
+ when /password/ then return :password
281
+ end
282
+
283
+ case type(method)
284
+ when :string then return :string
285
+ when :integer then return :number
286
+ when :float then return :number
287
+ when :decimal then return :number
288
+ when :timestamp then return :datetime
289
+ when :datetime then return :datetime
290
+ when :date then return :date
291
+ when :time then return :time
292
+ when :text then return :text
293
+ end
294
+
295
+ return :file if file?(method)
296
+
297
+ config.default_as
298
+ end
299
+
300
+ # Generate error messages by combining all errors on an object into a comma seperated string
301
+ # representation.
302
+ def error(method)
303
+ errors = @object.errors[method] if @object
304
+ errors.to_sentence if errors.present?
305
+ end
306
+
307
+ # Identify if error message exists for a given method by checking for the presence of the object
308
+ # followed by the presence of errors.
309
+ def error?(method)
310
+ @object.present? and @object.errors[method].present?
311
+ end
312
+
313
+ # Create an array from a string, a symbol, or an undefined value. The default is to return
314
+ # the value and assume it has already is valid.
315
+ def arrayorize(value)
316
+ case value
317
+ when nil then []
318
+ when String then value.to_s.split
319
+ when Symbol then value.to_s.split
320
+ else value
321
+ end
322
+ end
323
+
324
+ public
325
+
326
+ # Generates a wrapper around fields_form with :builder set to FormBuilder.
327
+ #
328
+ # Supports:
329
+ #
330
+ # * f.formula_fields_for(@user.company)
331
+ # * f.fieldsula_for(@user.company)
332
+ #
333
+ # Equivalent:
334
+ #
335
+ # * f.fields_for(@user.company, builder: Formula::FormBuilder))
336
+ #
337
+ # Usage:
338
+ #
339
+ # <% f.formula_fields_for(@user.company) do |company_f| %>
340
+ # <%= company_f.input :url %>
341
+ # <%= company_f.input :phone %>
342
+ # <% end %>
343
+ def formula_fields_for(record_or_name_or_array, *args, &block)
344
+ options = args.extract_options!
345
+ options[:builder] ||= self.class
346
+ fields_for(record_or_name_or_array, *(args << options), &block)
347
+ end
348
+
349
+ alias fieldsula_for formula_fields_for
350
+ end
351
+ end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Formula
4
+ module FormHelper
5
+ # Generates a wrapper around form_for with :builder set to Formula::FormBuilder.
6
+ #
7
+ # Supports:
8
+ #
9
+ # * formula_form_for(@user)
10
+ #
11
+ # Equivalent:
12
+ #
13
+ # * form_for(@user, builder: Formula::FormBuilder))
14
+ #
15
+ # Usage:
16
+ #
17
+ # <% formula_form_for(@user) do |f| %>
18
+ # <%= f.input :email %>
19
+ # <%= f.input :password %>
20
+ # <% end %>
21
+ def formula_form_for(record_or_name_or_array, *args, &proc)
22
+ options = args.extract_options!
23
+ options[:builder] ||= ::Formula::FormBuilder
24
+ form_for(record_or_name_or_array, *(args << options), &proc)
25
+ end
26
+
27
+ # Generates a wrapper around fields_for with :builder set to Formula::FormBuilder.
28
+ #
29
+ # Supports:
30
+ #
31
+ # * f.formula_fields_for(@user.company)
32
+ #
33
+ # Equivalent:
34
+ #
35
+ # * f.fields_for(@user.company, builder: Formula::FormulaFormBuilder))
36
+ #
37
+ # Usage:
38
+ #
39
+ # <% f.formula_fields_for(@user.company) do |company_f| %>
40
+ # <%= company_f.input :url %>
41
+ # <%= company_f.input :phone %>
42
+ # <% end %>
43
+ def formula_fields_for(record_or_name_or_array, *args, &block)
44
+ options = args.extract_options!
45
+ options[:builder] ||= ::Formula::FormBuilder
46
+ fields_for(record_or_name_or_array, *(args << options), &block)
47
+ end
48
+ end
49
+ end
@@ -1,10 +1,11 @@
1
- require 'formula'
1
+ # frozen_string_literal: true
2
+
2
3
  require 'rails'
3
4
 
4
5
  module Formula
5
6
  class Railtie < Rails::Railtie
6
7
  initializer 'formula.initialize' do
7
- ActionView::Base.send :include, Formula::FormulaFormHelper
8
+ ActionView::Base.include Formula::FormHelper
8
9
  end
9
10
  end
10
11
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Formula
2
- VERSION = "1.1.1"
4
+ VERSION = '2.0.0'
3
5
  end