lotus-helpers 0.1.0 → 0.2.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 +4 -4
- data/README.md +167 -1
- data/lib/lotus/helpers.rb +6 -0
- data/lib/lotus/helpers/form_helper.rb +423 -0
- data/lib/lotus/helpers/form_helper/form_builder.rb +790 -0
- data/lib/lotus/helpers/form_helper/html_node.rb +79 -0
- data/lib/lotus/helpers/form_helper/values.rb +38 -0
- data/lib/lotus/helpers/html_helper.rb +1 -1
- data/lib/lotus/helpers/html_helper/html_builder.rb +11 -2
- data/lib/lotus/helpers/html_helper/html_node.rb +2 -1
- data/lib/lotus/helpers/link_to_helper.rb +28 -0
- data/lib/lotus/helpers/number_formatting_helper.rb +220 -0
- data/lib/lotus/helpers/version.rb +1 -1
- data/lotus-helpers.gemspec +1 -1
- metadata +11 -5
@@ -0,0 +1,79 @@
|
|
1
|
+
require 'lotus/helpers/html_helper/html_node'
|
2
|
+
|
3
|
+
module Lotus
|
4
|
+
module Helpers
|
5
|
+
module FormHelper
|
6
|
+
# HTML form node
|
7
|
+
#
|
8
|
+
# @since x.x.x
|
9
|
+
# @api private
|
10
|
+
#
|
11
|
+
# @see Lotus::Helpers::HtmlHelper::HtmlNode
|
12
|
+
class HtmlNode < ::Lotus::Helpers::HtmlHelper::HtmlNode
|
13
|
+
# Initialize a new HTML form node
|
14
|
+
#
|
15
|
+
# @param name [Symbol,String] the name of the tag
|
16
|
+
# @param content [String,Proc,Lotus::Helpers::HtmlHelper::FormBuilder,NilClass] the optional content
|
17
|
+
# @param attributes [Hash,NilClass] the optional tag attributes
|
18
|
+
# @param options [Hash] a set of data
|
19
|
+
#
|
20
|
+
# @return [Lotus::Helpers::FormHelper::HtmlNode]
|
21
|
+
#
|
22
|
+
# @since x.x.x
|
23
|
+
# @api private
|
24
|
+
def initialize(name, content, attributes, options)
|
25
|
+
super
|
26
|
+
|
27
|
+
@verb = options.fetch(:verb, nil)
|
28
|
+
@csrf_token = options.fetch(:csrf_token, nil)
|
29
|
+
|
30
|
+
@builder = FormBuilder.new(
|
31
|
+
options.fetch(:name),
|
32
|
+
options.fetch(:values)
|
33
|
+
)
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
# Resolve the (nested) content
|
38
|
+
#
|
39
|
+
# @return [String] the content
|
40
|
+
#
|
41
|
+
# @since x.x.x
|
42
|
+
# @api private
|
43
|
+
#
|
44
|
+
# @see Lotus::Helpers::HtmlHelper::HtmlNode#content
|
45
|
+
def content
|
46
|
+
_method_override!
|
47
|
+
_csrf_protection!
|
48
|
+
super
|
49
|
+
end
|
50
|
+
|
51
|
+
# Inject a hidden field to make Method Override possible
|
52
|
+
#
|
53
|
+
# @since x.x.x
|
54
|
+
# @api private
|
55
|
+
def _method_override!
|
56
|
+
return if @verb.nil?
|
57
|
+
|
58
|
+
verb = @verb
|
59
|
+
@builder.resolve do
|
60
|
+
input(type: :hidden, name: :_method, value: verb)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
# Inject a hidden field for CSRF Protection token
|
65
|
+
#
|
66
|
+
# @since x.x.x
|
67
|
+
# @api private
|
68
|
+
def _csrf_protection!
|
69
|
+
return if @csrf_token.nil?
|
70
|
+
|
71
|
+
_csrf_token = @csrf_token
|
72
|
+
@builder.resolve do
|
73
|
+
input(type: :hidden, name: FormHelper::CSRF_TOKEN, value: _csrf_token)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'lotus/utils/hash'
|
2
|
+
|
3
|
+
module Lotus
|
4
|
+
module Helpers
|
5
|
+
module FormHelper
|
6
|
+
class Values
|
7
|
+
GET_SEPARATOR = '.'.freeze
|
8
|
+
|
9
|
+
def initialize(values, params)
|
10
|
+
@values = Utils::Hash.new(values).stringify!
|
11
|
+
@params = params
|
12
|
+
end
|
13
|
+
|
14
|
+
def get(key)
|
15
|
+
@params.get(key) || _get_from_values(key)
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
def _get_from_values(key)
|
20
|
+
initial_key, *keys = key.to_s.split(GET_SEPARATOR)
|
21
|
+
result = @values[initial_key]
|
22
|
+
|
23
|
+
Array(keys).each do |k|
|
24
|
+
break if result.nil?
|
25
|
+
|
26
|
+
result = if result.respond_to?(k)
|
27
|
+
result.public_send(k)
|
28
|
+
else
|
29
|
+
nil
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
result
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -81,7 +81,7 @@ module Lotus
|
|
81
81
|
# input type: 'submit', value: 'Save changes'
|
82
82
|
# end
|
83
83
|
# # =>
|
84
|
-
# #<form action="/users" method="POST">
|
84
|
+
# #<form action="/users" method="POST" accept-charset="utf-8">
|
85
85
|
# # <div>
|
86
86
|
# # <label for="user-first-name">First name</label>
|
87
87
|
# # <input type="text" id="user-first-name" name="user[first_name]" value="L">
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'lotus/utils' # RUBY_VERSION >= '2.2'
|
2
|
+
require 'lotus/utils/class_attribute'
|
2
3
|
require 'lotus/utils/escape'
|
3
4
|
require 'lotus/helpers/html_helper/empty_html_node'
|
4
5
|
require 'lotus/helpers/html_helper/html_node'
|
@@ -149,7 +150,7 @@ module Lotus
|
|
149
150
|
CONTENT_TAGS.each do |tag|
|
150
151
|
class_eval %{
|
151
152
|
def #{ tag }(content = nil, attributes = nil, &blk)
|
152
|
-
@nodes <<
|
153
|
+
@nodes << self.class.html_node.new(:#{ tag }, blk || content, attributes || content, options)
|
153
154
|
self
|
154
155
|
end
|
155
156
|
}
|
@@ -164,6 +165,11 @@ module Lotus
|
|
164
165
|
}
|
165
166
|
end
|
166
167
|
|
168
|
+
include Utils::ClassAttribute
|
169
|
+
|
170
|
+
class_attribute :html_node
|
171
|
+
self.html_node = ::Lotus::Helpers::HtmlHelper::HtmlNode
|
172
|
+
|
167
173
|
# Initialize a new builder
|
168
174
|
#
|
169
175
|
# @return [Lotus::Helpers::HtmlHelper::HtmlBuilder] the builder
|
@@ -174,6 +180,9 @@ module Lotus
|
|
174
180
|
@nodes = []
|
175
181
|
end
|
176
182
|
|
183
|
+
def options
|
184
|
+
end
|
185
|
+
|
177
186
|
# Define a custom tag
|
178
187
|
#
|
179
188
|
# @param name [Symbol,String] the name of the tag
|
@@ -217,7 +226,7 @@ module Lotus
|
|
217
226
|
# # hello
|
218
227
|
# #</custom>
|
219
228
|
def tag(name, content = nil, attributes = nil, &blk)
|
220
|
-
@nodes << HtmlNode.new(name, blk || content, attributes || content)
|
229
|
+
@nodes << HtmlNode.new(name, blk || content, attributes || content, options)
|
221
230
|
self
|
222
231
|
end
|
223
232
|
|
@@ -15,9 +15,10 @@ module Lotus
|
|
15
15
|
# @param name [Symbol,String] the name of the tag
|
16
16
|
# @param content [String,Proc,Lotus::Helpers::HtmlHelper::HtmlBuilder,NilClass] the optional content
|
17
17
|
# @param attributes [Hash,NilClass] the optional tag attributes
|
18
|
+
# @param options [Hash] a optional set of data
|
18
19
|
#
|
19
20
|
# @return [Lotus::Helpers::HtmlHelper::HtmlNode]
|
20
|
-
def initialize(name, content, attributes)
|
21
|
+
def initialize(name, content, attributes, options = {})
|
21
22
|
@builder = HtmlBuilder.new
|
22
23
|
@name = name
|
23
24
|
@content = case content
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'lotus/helpers/html_helper'
|
2
|
+
|
3
|
+
module Lotus
|
4
|
+
module Helpers
|
5
|
+
# LinkTo Helper
|
6
|
+
#
|
7
|
+
# Including <tt>Lotus::Helpers::LinkTo</tt> will include the `link_to` method.
|
8
|
+
#
|
9
|
+
# @since x.x.x
|
10
|
+
#
|
11
|
+
# @see Lotus::Helpers::HtmlHelper#html
|
12
|
+
#
|
13
|
+
# @example Usage
|
14
|
+
# # 1
|
15
|
+
# link_to('home', '/') # => <a href="/">home</a>
|
16
|
+
#
|
17
|
+
# # 2
|
18
|
+
# link_to('users', :users_path, class: 'my_users') # => <a href="/users" class="my_users">users</div>
|
19
|
+
module LinkToHelper
|
20
|
+
include Lotus::Helpers::HtmlHelper
|
21
|
+
|
22
|
+
def link_to(content, url, options = {}, &blk)
|
23
|
+
options[:href] = url
|
24
|
+
html.a(blk || content, options).to_s
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,220 @@
|
|
1
|
+
module Lotus
|
2
|
+
module Helpers
|
3
|
+
# Number formatter
|
4
|
+
#
|
5
|
+
# You can include this module inside your view and
|
6
|
+
# the view will have access all methods.
|
7
|
+
#
|
8
|
+
# By including <tt>Lotus::Helpers::NumberFormattingHelper</tt> it will
|
9
|
+
# inject private method: <tt>format_number</tt>.
|
10
|
+
#
|
11
|
+
# @since x.x.x
|
12
|
+
module NumberFormattingHelper
|
13
|
+
private
|
14
|
+
# Format the given number, according to the options
|
15
|
+
#
|
16
|
+
# It accepts a number (<tt>Numeric</tt>) or a string representation.
|
17
|
+
#
|
18
|
+
# If an integer is given, no precision is applied.
|
19
|
+
# For the rest of the numbers, it will format as a float representation.
|
20
|
+
# This is the case of: <tt>Float</tt>, <tt>BigDecimal</tt>,
|
21
|
+
# <tt>Complex</tt>, <tt>Rational</tt>.
|
22
|
+
#
|
23
|
+
# If the argument cannot be coerced into a number, it will raise a
|
24
|
+
# <tt>TypeError</tt>.
|
25
|
+
#
|
26
|
+
# @param number [Numeric,String] the number to be formatted
|
27
|
+
#
|
28
|
+
# @return [String] formatted number
|
29
|
+
#
|
30
|
+
# @raise [TypeError] if number can't be formatted
|
31
|
+
#
|
32
|
+
# @since x.x.x
|
33
|
+
#
|
34
|
+
# @example
|
35
|
+
# require 'lotus/helpers/number_formatter_helper'
|
36
|
+
#
|
37
|
+
# class Checkout
|
38
|
+
# include Lotus::Helpers::NumberFormattingHelper
|
39
|
+
#
|
40
|
+
# def total
|
41
|
+
# format_number 1999.99
|
42
|
+
# end
|
43
|
+
#
|
44
|
+
# def euros
|
45
|
+
# format_number 1256.95, delimiter: '.', separator: ','
|
46
|
+
# end
|
47
|
+
#
|
48
|
+
# def visitors_count
|
49
|
+
# format_number '1000'
|
50
|
+
# end
|
51
|
+
# end
|
52
|
+
#
|
53
|
+
# view = Checkout.new
|
54
|
+
#
|
55
|
+
# view.total
|
56
|
+
# # => "1,999.99"
|
57
|
+
#
|
58
|
+
# view.euros
|
59
|
+
# # => "1.256,95"
|
60
|
+
#
|
61
|
+
# view.visitors_count
|
62
|
+
# # => "1,000"
|
63
|
+
def format_number(number, options = {})
|
64
|
+
Formatter.new(number, options).format
|
65
|
+
end
|
66
|
+
|
67
|
+
# Formatter
|
68
|
+
#
|
69
|
+
# @since x.x.x
|
70
|
+
# @api private
|
71
|
+
class Formatter
|
72
|
+
# Regex to delimitate integer part of a number
|
73
|
+
#
|
74
|
+
# @return [Regexp] the delimitation regex
|
75
|
+
#
|
76
|
+
# @since x.x.x
|
77
|
+
# @api private
|
78
|
+
#
|
79
|
+
# @see Lotus::Helpers::NumberFormatter::Formatter#delimitate
|
80
|
+
DELIMITATION_REGEX = /(\d)(?=(\d{3})+$)/
|
81
|
+
|
82
|
+
# Regex to guess if the number is a integer
|
83
|
+
#
|
84
|
+
# @return [Regexp] the guessing regex
|
85
|
+
#
|
86
|
+
# @since x.x.x
|
87
|
+
# @api private
|
88
|
+
#
|
89
|
+
# @see Lotus::Helpers::NumberFormatter::Formatter#to_number
|
90
|
+
INTEGER_REGEXP = /\A[\d]+\z/
|
91
|
+
|
92
|
+
# Default separator
|
93
|
+
#
|
94
|
+
# @return [String] default separator
|
95
|
+
#
|
96
|
+
# @since x.x.x
|
97
|
+
# @api private
|
98
|
+
DEFAULT_SEPARATOR = '.'.freeze
|
99
|
+
|
100
|
+
# Default delimiter
|
101
|
+
#
|
102
|
+
# @return [String] default delimiter
|
103
|
+
#
|
104
|
+
# @since x.x.x
|
105
|
+
# @api private
|
106
|
+
DEFAULT_DELIMITER = ','.freeze
|
107
|
+
|
108
|
+
# Default precision
|
109
|
+
#
|
110
|
+
# @return [String] default precision
|
111
|
+
#
|
112
|
+
# @since x.x.x
|
113
|
+
# @api private
|
114
|
+
DEFAULT_PRECISION = 2
|
115
|
+
|
116
|
+
# Initialize a new formatter
|
117
|
+
#
|
118
|
+
# @param number [Numeric,String] the number to format
|
119
|
+
# @param options [Hash] options for number formatting
|
120
|
+
# @option options [String] :delimiter hundred delimiter
|
121
|
+
# @option options [String] :separator fractional part delimiter
|
122
|
+
# @option options [Integer] :precision rounding precision
|
123
|
+
#
|
124
|
+
# @since x.x.x
|
125
|
+
# @api private
|
126
|
+
#
|
127
|
+
# @see Lotus::Helpers::NumberFormatter::Formatter::DEFAULT_DELIMITER
|
128
|
+
# @see Lotus::Helpers::NumberFormatter::Formatter::DEFAULT_SEPARATOR
|
129
|
+
# @see Lotus::Helpers::NumberFormatter::Formatter::DEFAULT_PRECISION
|
130
|
+
def initialize(number, options)
|
131
|
+
@number = number
|
132
|
+
@delimiter = options.fetch(:delimiter, DEFAULT_DELIMITER)
|
133
|
+
@separator = options.fetch(:separator, DEFAULT_SEPARATOR)
|
134
|
+
@precision = options.fetch(:precision, DEFAULT_PRECISION)
|
135
|
+
end
|
136
|
+
|
137
|
+
# Format number according to the specified options
|
138
|
+
#
|
139
|
+
# @return [String] formatted number
|
140
|
+
#
|
141
|
+
# @raise [TypeError] if number can't be formatted
|
142
|
+
#
|
143
|
+
# @since x.x.x
|
144
|
+
# @api private
|
145
|
+
def format
|
146
|
+
parts.join(@separator)
|
147
|
+
end
|
148
|
+
|
149
|
+
private
|
150
|
+
|
151
|
+
# Return integer and fractional parts
|
152
|
+
#
|
153
|
+
# @return [Array] parts
|
154
|
+
#
|
155
|
+
# @since x.x.x
|
156
|
+
# @api private
|
157
|
+
def parts
|
158
|
+
integer_part, fractional_part = to_str.split(DEFAULT_SEPARATOR)
|
159
|
+
[delimitate(integer_part), fractional_part].compact
|
160
|
+
end
|
161
|
+
|
162
|
+
# Delimitate the given part
|
163
|
+
#
|
164
|
+
# @return [String] delimitated string
|
165
|
+
#
|
166
|
+
# @since x.x.x
|
167
|
+
# @api private
|
168
|
+
def delimitate(part)
|
169
|
+
part.gsub(DELIMITATION_REGEX) { |digit| "#{digit}#{@delimiter}" }
|
170
|
+
end
|
171
|
+
|
172
|
+
# String coercion
|
173
|
+
#
|
174
|
+
# @return [String] coerced number
|
175
|
+
#
|
176
|
+
# @raise [TypeError] if number can't be formatted
|
177
|
+
#
|
178
|
+
# @since x.x.x
|
179
|
+
# @api private
|
180
|
+
def to_str
|
181
|
+
to_number.to_s
|
182
|
+
end
|
183
|
+
|
184
|
+
# Numeric coercion
|
185
|
+
#
|
186
|
+
# @return [Numeric] coerced number
|
187
|
+
#
|
188
|
+
# @raise [TypeError] if number can't be formatted
|
189
|
+
#
|
190
|
+
# @since x.x.x
|
191
|
+
# @api private
|
192
|
+
def to_number
|
193
|
+
case @number
|
194
|
+
when NilClass
|
195
|
+
raise TypeError
|
196
|
+
when ->(n) { n.to_s.match(INTEGER_REGEXP) }
|
197
|
+
Utils::Kernel.Integer(@number)
|
198
|
+
else
|
199
|
+
Utils::Kernel.Float(rounded_number)
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
# Round number in case we need to return a <tt>Float</tt> representation.
|
204
|
+
# If <tt>@number</tt> doesn't respond to <tt>#round</tt> return the number as it is.
|
205
|
+
#
|
206
|
+
# @return [Float,Complex,Rational,BigDecimal] rounded number, if applicable
|
207
|
+
#
|
208
|
+
# @since x.x.x
|
209
|
+
# @api private
|
210
|
+
def rounded_number
|
211
|
+
if @number.respond_to?(:round)
|
212
|
+
@number.round(@precision)
|
213
|
+
else
|
214
|
+
@number
|
215
|
+
end
|
216
|
+
end
|
217
|
+
end
|
218
|
+
end
|
219
|
+
end
|
220
|
+
end
|
data/lotus-helpers.gemspec
CHANGED
@@ -19,7 +19,7 @@ Gem::Specification.new do |spec|
|
|
19
19
|
spec.require_paths = ['lib']
|
20
20
|
spec.required_ruby_version = '>= 2.0.0'
|
21
21
|
|
22
|
-
spec.add_dependency 'lotus-utils', '~> 0.
|
22
|
+
spec.add_dependency 'lotus-utils', '~> 0.5'
|
23
23
|
|
24
24
|
spec.add_development_dependency 'bundler', '~> 1.6'
|
25
25
|
spec.add_development_dependency 'rake', '~> 10.0'
|