lotus-helpers 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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'