formula 1.1.1 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/Gemfile +11 -0
- data/README.md +71 -0
- data/bin/rubocop +8 -0
- data/bin/test +5 -0
- data/lib/formula/config.rb +136 -0
- data/lib/formula/form_builder.rb +351 -0
- data/lib/formula/form_helper.rb +49 -0
- data/lib/formula/railtie.rb +3 -2
- data/lib/formula/version.rb +3 -1
- data/lib/formula.rb +12 -495
- metadata +37 -17
- data/LICENSE +0 -20
- data/README.rdoc +0 -72
- data/Rakefile +0 -32
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 8e753004d2065d2a0aa15c73ac8393b54de9ae40086f2f5da874e0cd1a0ccd8a
|
4
|
+
data.tar.gz: 21797db2580b4ae567942e4b3c36e2c86caed7645d58ecd4ba10cecb25449ad5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 59d014229aa1940f2b0d08b263d6bc49ab9caa836b4e4b993bc3c9407b2544fd789e8a36f1e324a19f467d8895b23ab3d15fa14fd3af27c77b426abe25c908b4
|
7
|
+
data.tar.gz: cd47a5b0382b1bf898a2e0691c3234504e016ab29d96496290127903ae3bafe6140cedd651e554f3f2a626ecf43293d1cb4fc318ef833e236417cca9bd11b522
|
data/Gemfile
ADDED
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,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
|
data/lib/formula/railtie.rb
CHANGED
@@ -1,10 +1,11 @@
|
|
1
|
-
|
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.
|
8
|
+
ActionView::Base.include Formula::FormHelper
|
8
9
|
end
|
9
10
|
end
|
10
11
|
end
|
data/lib/formula/version.rb
CHANGED