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.
@@ -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 << HtmlNode.new(:#{ tag }, blk || content, attributes || content)
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
@@ -3,6 +3,6 @@ module Lotus
3
3
  # Define version
4
4
  #
5
5
  # @since 0.1.0
6
- VERSION = '0.1.0'.freeze
6
+ VERSION = '0.2.0'.freeze
7
7
  end
8
8
  end
@@ -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.4'
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'