tzispa_helpers 0.2.2 → 0.3.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/CHANGELOG.md +4 -0
- data/lib/tzispa/helpers.rb +8 -7
- data/lib/tzispa/helpers/date_time.rb +4 -1
- data/lib/tzispa/helpers/error_view.rb +47 -32
- data/lib/tzispa/helpers/html.rb +3 -5
- data/lib/tzispa/helpers/mime.rb +1 -1
- data/lib/tzispa/helpers/pattern.rb +19 -21
- data/lib/tzispa/helpers/provider.rb +5 -8
- data/lib/tzispa/helpers/request.rb +42 -36
- data/lib/tzispa/helpers/requirer.rb +6 -4
- data/lib/tzispa/helpers/response.rb +39 -71
- data/lib/tzispa/helpers/security.rb +21 -36
- data/lib/tzispa/helpers/services/content_type.rb +60 -0
- data/lib/tzispa/helpers/services/error_view.rb +38 -0
- data/lib/tzispa/helpers/services/send_file.rb +64 -0
- data/lib/tzispa/helpers/session.rb +60 -0
- data/lib/tzispa/helpers/session_flash_bag.rb +64 -0
- data/lib/tzispa/helpers/sign_requirer.rb +2 -3
- data/lib/tzispa/helpers/text.rb +54 -49
- data/lib/tzispa/helpers/version.rb +1 -1
- metadata +7 -3
- data/lib/tzispa/helpers/hash_trans.rb +0 -18
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3e89639a5292d45bd73bb24c089a7d2e12a5af5d
|
4
|
+
data.tar.gz: a913cbe727b39b40d9e0fdf9cf893c820a42baaf
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 45d66dc9fec88bdb30d7257a82bceb59bc3fb4746b22788e009d0d9f965a26ca041141465f82ffba50b67e0f921ac8b8d9061c9a499a06567d8f45bd5e9617b7
|
7
|
+
data.tar.gz: b0c6b9d2f8054c820ea478c3f870811c26b6719ba87b14160bb7be4a902be31a20506bfdfc3e3a2dd48c3c1bbd3472e1ca5403f69f1b7ea8477b0b75569f85cd
|
data/CHANGELOG.md
CHANGED
data/lib/tzispa/helpers.rb
CHANGED
@@ -1,19 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Tzispa
|
2
4
|
module Helpers
|
3
5
|
|
4
|
-
require 'tzispa/helpers/
|
5
|
-
require 'tzispa/helpers/
|
6
|
+
require 'tzispa/helpers/date_time'
|
7
|
+
require 'tzispa/helpers/error_view'
|
6
8
|
require 'tzispa/helpers/html'
|
7
|
-
require 'tzispa/helpers/mail'
|
8
|
-
require 'tzispa/helpers/mime'
|
9
9
|
require 'tzispa/helpers/pattern'
|
10
|
+
require 'tzispa/helpers/provider'
|
10
11
|
require 'tzispa/helpers/request'
|
12
|
+
require 'tzispa/helpers/requirer'
|
11
13
|
require 'tzispa/helpers/response'
|
12
14
|
require 'tzispa/helpers/security'
|
15
|
+
require 'tzispa/helpers/sign_requirer'
|
13
16
|
require 'tzispa/helpers/text'
|
14
|
-
require 'tzispa/helpers/
|
15
|
-
require 'tzispa/helpers/error_view'
|
16
|
-
require 'tzispa/helpers/recaptcha'
|
17
|
+
require 'tzispa/helpers/version'
|
17
18
|
|
18
19
|
end
|
19
20
|
end
|
@@ -1,9 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Tzispa
|
2
4
|
module Helpers
|
3
5
|
module DateTime
|
4
6
|
|
5
7
|
def date_months_diff(date1, date2)
|
6
|
-
(date2.year - date1.year) * 12 +
|
8
|
+
(date2.year - date1.year) * 12 +
|
9
|
+
date2.month - date1.month - (date2.day >= date1.day ? 0 : 1)
|
7
10
|
end
|
8
11
|
|
9
12
|
def date_days_diff(date1, date2)
|
@@ -1,49 +1,64 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'tzispa/rig/template'
|
2
4
|
require 'tzispa/version'
|
5
|
+
require 'tzispa/helpers/services/error_view'
|
3
6
|
|
4
7
|
module Tzispa
|
5
8
|
module Helpers
|
6
9
|
module ErrorView
|
7
10
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
11
|
+
ERROR_HEADER = <<-ERRORHEADER
|
12
|
+
<head>
|
13
|
+
<meta charset="utf-8" />
|
14
|
+
<style> html {background:#cccccc; font-family:Arial; font-size:15px; color:#555;} body {width:75%; max-width:1200px; margin:18px auto; background:#fff; border-radius:6px; padding:32px 24px;} #main {margin:auto; } ul{list-style:none; margin:0; padding:0;} li{font-style:italic; color:#666;} h1 {color:#2ECC71;} </style>
|
15
|
+
</head>
|
16
|
+
ERRORHEADER
|
17
|
+
|
18
|
+
ERROR_PLATFORM_VERSIONS = <<-ERRORPVERSION
|
19
|
+
<h6>#{Tzispa::FRAMEWORK_NAME} #{Tzispa::VERSION}</h6>
|
20
|
+
ERRORPVERSION
|
21
|
+
|
22
|
+
def debug_info(ex = nil, status: 500)
|
23
|
+
String.new.tap do |text|
|
24
|
+
text << '<!DOCTYPE html><html lang="es">'
|
25
|
+
text << ERROR_HEADER << '<body>'
|
26
|
+
text << ERROR_PLATFORM_VERSIONS
|
27
|
+
text << if ex
|
28
|
+
srx = Tzispa::Helpers::Services::ErrorView.new ex
|
29
|
+
"<h1>#{srx.error_header}\n #{srx.error_backtrace_list}"
|
30
|
+
else
|
31
|
+
"<h1>Error #{status}</h1>\nSe ha producido un error indeterminado"
|
32
|
+
end
|
23
33
|
text << '</body></html>'
|
24
|
-
|
34
|
+
end
|
25
35
|
end
|
26
36
|
|
27
37
|
def error_page(domain, status: 500)
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
text << '<!DOCTYPE html>'
|
34
|
-
text << '<html lang="es"><head>'
|
35
|
-
text << '<meta charset="utf-8" />'
|
36
|
-
text << '<style> html {background:#cccccc; font-family:Arial; font-size:15px; color:#555;} body {width:75%; max-width:1200px; margin:18px auto; background:#fff; border-radius:6px; padding:32px 24px;} #main {margin:auto; } h1 {color:#2ECC71; font-size:4em; text-align:center;} </style>'
|
37
|
-
text << '</head><body>'
|
38
|
-
text << '<div id="main">'
|
39
|
-
text << "<h5>#{Tzispa::FRAMEWORK_NAME} #{Tzispa::VERSION}</h5>\n"
|
40
|
-
text << "<h1>Error #{status}</h1>\n"
|
41
|
-
text << '</div>'
|
42
|
-
text << '</body></html>'
|
43
|
-
}
|
38
|
+
error_file = "#{domain.path}/error/#{status}.htm"
|
39
|
+
if (ef = Tzispa::Rig::File.new(error_file)) && ef.exist?
|
40
|
+
ef.load!.content
|
41
|
+
else
|
42
|
+
error_default
|
44
43
|
end
|
45
44
|
end
|
46
45
|
|
46
|
+
def error_log(ex)
|
47
|
+
Tzispa::Helpers::Services::ErrorView.new(ex).error_backtrace_log
|
48
|
+
end
|
49
|
+
|
50
|
+
def error_default
|
51
|
+
String.new.tap do |text|
|
52
|
+
text << '<!DOCTYPE html><html lang="es">'
|
53
|
+
text << ERROR_HEADER << '<body>'
|
54
|
+
text << '</head><body>'
|
55
|
+
text << '<div id="main">'
|
56
|
+
text << ERROR_PLATFORM_VERSIONS
|
57
|
+
text << "<h1>Error #{status}</h1>\n"
|
58
|
+
text << '</div>'
|
59
|
+
text << '</body></html>'
|
60
|
+
end
|
61
|
+
end
|
47
62
|
|
48
63
|
end
|
49
64
|
end
|
data/lib/tzispa/helpers/html.rb
CHANGED
@@ -20,11 +20,11 @@ module Tzispa
|
|
20
20
|
end
|
21
21
|
|
22
22
|
def html_escape(str)
|
23
|
-
CGI
|
23
|
+
CGI.escapeHTML str
|
24
24
|
end
|
25
25
|
|
26
26
|
def html_unescape(str)
|
27
|
-
CGI
|
27
|
+
CGI.unescapeHTML str
|
28
28
|
end
|
29
29
|
|
30
30
|
def html_urlencode(str)
|
@@ -36,10 +36,9 @@ module Tzispa
|
|
36
36
|
end
|
37
37
|
|
38
38
|
def html_strip(source)
|
39
|
-
source.gsub(/<\/?[^>]
|
39
|
+
source.gsub(%r{/<\/?[^>]*>/}, '')
|
40
40
|
end
|
41
41
|
|
42
|
-
|
43
42
|
#
|
44
43
|
# $Id: sanitize.rb 3 2005-04-05 12:51:14Z dwight $
|
45
44
|
#
|
@@ -147,7 +146,6 @@ module Tzispa
|
|
147
146
|
result
|
148
147
|
end
|
149
148
|
|
150
|
-
|
151
149
|
end
|
152
150
|
end
|
153
151
|
end
|
data/lib/tzispa/helpers/mime.rb
CHANGED
@@ -9,7 +9,7 @@ module Tzispa
|
|
9
9
|
def mime_type(type, value = nil)
|
10
10
|
return type if type.nil?
|
11
11
|
return type.to_s if type.to_s.include?('/')
|
12
|
-
type = ".#{type}" unless type.to_s[0] ==
|
12
|
+
type = ".#{type}" unless type.to_s[0] == '.'
|
13
13
|
return Rack::Mime.mime_type(type, nil) unless value
|
14
14
|
Rack::Mime::MIME_TYPES[type] = value
|
15
15
|
end
|
@@ -8,49 +8,47 @@ module Tzispa
|
|
8
8
|
|
9
9
|
include Tzispa::Helpers::Html
|
10
10
|
|
11
|
-
def pattern_select_hours(selected=nil)
|
11
|
+
def pattern_select_hours(selected = nil)
|
12
12
|
selected &&= selected.to_i
|
13
|
-
|
14
|
-
(0..23).map
|
13
|
+
proc do
|
14
|
+
(0..23).map do |hour|
|
15
15
|
loop_item(
|
16
16
|
value: hour,
|
17
17
|
text: hour.to_s.rjust(2, '0'),
|
18
|
-
selected: html_selected(
|
18
|
+
selected: html_selected(selected == hour)
|
19
19
|
)
|
20
|
-
|
21
|
-
|
20
|
+
end
|
21
|
+
end
|
22
22
|
end
|
23
23
|
|
24
|
-
def pattern_select_minutes(selected=nil)
|
24
|
+
def pattern_select_minutes(selected = nil)
|
25
25
|
selected &&= selected.to_i
|
26
|
-
|
27
|
-
(0..59).map
|
26
|
+
proc do
|
27
|
+
(0..59).map do |minute|
|
28
28
|
loop_item(
|
29
29
|
value: minute,
|
30
30
|
text: minute.to_s.rjust(2, '0'),
|
31
|
-
selected: html_selected(
|
31
|
+
selected: html_selected(selected == minute)
|
32
32
|
)
|
33
|
-
|
34
|
-
|
33
|
+
end
|
34
|
+
end
|
35
35
|
end
|
36
36
|
|
37
|
-
def pattern_select_year(first, last, selected=nil
|
37
|
+
def pattern_select_year(first, last, selected = nil)
|
38
38
|
selected &&= selected.to_i
|
39
|
-
|
39
|
+
proc do
|
40
40
|
ryear = (first..last)
|
41
|
-
enum_year = first > last ?
|
42
|
-
enum_year.map
|
41
|
+
enum_year = first > last ? ryear.first.downto(ryear.last) : ryear.first.to(ryear.last)
|
42
|
+
enum_year.map do |year|
|
43
43
|
loop_item(
|
44
44
|
value: year,
|
45
45
|
text: year,
|
46
|
-
selected: html_selected(
|
46
|
+
selected: html_selected(selected == year)
|
47
47
|
)
|
48
|
-
|
49
|
-
|
48
|
+
end
|
49
|
+
end
|
50
50
|
end
|
51
51
|
|
52
|
-
|
53
|
-
|
54
52
|
end
|
55
53
|
end
|
56
54
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Tzispa
|
2
4
|
module Helpers
|
3
5
|
module Provider
|
@@ -11,13 +13,10 @@ module Tzispa
|
|
11
13
|
end
|
12
14
|
|
13
15
|
module ClassMethods
|
14
|
-
|
15
16
|
def provides(*args)
|
16
|
-
(@provides ||=
|
17
|
-
args&.each { |s|
|
18
|
-
|
19
|
-
}
|
20
|
-
}
|
17
|
+
(@provides ||= {}).tap do |prv|
|
18
|
+
args&.each { |s| prv[s.to_sym] = s }
|
19
|
+
end
|
21
20
|
end
|
22
21
|
|
23
22
|
def provides?(verb)
|
@@ -28,10 +27,8 @@ module Tzispa
|
|
28
27
|
def provides_map(source, dest)
|
29
28
|
provides[source] = dest
|
30
29
|
end
|
31
|
-
|
32
30
|
end
|
33
31
|
|
34
|
-
|
35
32
|
end
|
36
33
|
end
|
37
34
|
end
|
@@ -6,59 +6,65 @@ module Tzispa
|
|
6
6
|
module Helpers
|
7
7
|
module Request
|
8
8
|
|
9
|
-
using Tzispa::Utils
|
9
|
+
using Tzispa::Utils::TzString
|
10
10
|
|
11
11
|
def request_data(fields)
|
12
|
-
|
13
|
-
fields.each
|
12
|
+
{}.tap do |data|
|
13
|
+
fields.each do |name|
|
14
14
|
macro_field = name.split('@:')
|
15
15
|
macro = macro_field.first.to_sym if macro_field.length == 2
|
16
16
|
field = macro_field.length == 2 ? macro_field.last : macro_field.first
|
17
|
-
field
|
18
|
-
|
19
|
-
|
20
|
-
value = String == context.request[src] ? String.unescape_html(context.request[src]) : context.request[src]
|
21
|
-
data[dest.to_sym] = macro ? send(macro, value) : value
|
22
|
-
}
|
23
|
-
}
|
24
|
-
}
|
17
|
+
build_field field, macro, data
|
18
|
+
end
|
19
|
+
end
|
25
20
|
end
|
26
21
|
|
27
22
|
def request_data_object(data_object:, fields:)
|
28
|
-
data_object.tap
|
29
|
-
fields.each
|
23
|
+
data_object.tap do |data|
|
24
|
+
fields.each do |name|
|
30
25
|
macro_field = name.split('@:')
|
31
26
|
macro = macro_field.first.to_sym if macro_field.length == 2
|
32
27
|
field = macro_field.length == 2 ? macro_field.last : macro_field.first
|
33
|
-
field
|
34
|
-
|
35
|
-
|
36
|
-
value = String == context.request[src] ? String.unescape_html(context.request[src]) : context.request[src]
|
37
|
-
data.send "#{dest}=".to_sym, macro ? send(macro, value) : value
|
38
|
-
}
|
39
|
-
}
|
40
|
-
}
|
28
|
+
build_field field, macro, data
|
29
|
+
end
|
30
|
+
end
|
41
31
|
end
|
42
32
|
|
43
33
|
def request_file_upload(request_file:, destination_path:, save_as: nil, keep_ext: true)
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
end
|
58
|
-
{ name: filename, ext: fileext, path: dest_file, size: ::File.size(dest_file), type: filetype }
|
34
|
+
return unless request_file
|
35
|
+
fileext = File.extname(request_file[:filename]).downcase
|
36
|
+
filetype = request_file[:type]
|
37
|
+
save_ext = fileext if keep_ext
|
38
|
+
filename = (save_as ? "#{save_as}#{save_ext}" : request_file[:filename])
|
39
|
+
tempfile = request_file[:tempfile]
|
40
|
+
dest_file = "#{destination_path}/#{filename}"
|
41
|
+
begin
|
42
|
+
FileUtils.mkdir_p(destination_path) unless File.exist?(destination_path)
|
43
|
+
FileUtils.cp tempfile.path, dest_file
|
44
|
+
ensure
|
45
|
+
tempfile.close
|
46
|
+
tempfile.unlink
|
59
47
|
end
|
48
|
+
{ name: filename, ext: fileext, path: dest_file,
|
49
|
+
size: ::File.size(dest_file), type: filetype }
|
60
50
|
end
|
61
51
|
|
52
|
+
def build_field(field, macro, data)
|
53
|
+
field.split(':').tap do |src, dest|
|
54
|
+
dest ||= src
|
55
|
+
value = if String == request[src]
|
56
|
+
String.unescape_html(request[src])
|
57
|
+
else
|
58
|
+
request[src]
|
59
|
+
end
|
60
|
+
value = macro ? send(macro, value) : value
|
61
|
+
if data.is_a? ::Hash
|
62
|
+
data[dest.to_sym] = value
|
63
|
+
else
|
64
|
+
data.send "#{dest}=".to_sym, value
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
62
68
|
|
63
69
|
end
|
64
70
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Tzispa
|
2
4
|
module Helpers
|
3
5
|
module Requirer
|
@@ -7,7 +9,7 @@ module Tzispa
|
|
7
9
|
end
|
8
10
|
|
9
11
|
def required?(target, value)
|
10
|
-
self.class.required? target
|
12
|
+
self.class.required? target, value
|
11
13
|
end
|
12
14
|
|
13
15
|
def required_valid?(target, value)
|
@@ -17,10 +19,10 @@ module Tzispa
|
|
17
19
|
module ClassMethods
|
18
20
|
|
19
21
|
def required(target, value, &block)
|
20
|
-
@required ||=
|
21
|
-
(@required[target] ||=
|
22
|
+
@required ||= {}
|
23
|
+
(@required[target] ||= {}).tap do |reqt|
|
22
24
|
reqt[value] = block || true
|
23
|
-
|
25
|
+
end
|
24
26
|
end
|
25
27
|
|
26
28
|
def required?(target, value)
|
@@ -2,6 +2,8 @@
|
|
2
2
|
|
3
3
|
require 'uri'
|
4
4
|
require_relative 'mime'
|
5
|
+
require_relative 'services/send_file'
|
6
|
+
require_relative 'services/content_type'
|
5
7
|
|
6
8
|
module Tzispa
|
7
9
|
module Helpers
|
@@ -23,10 +25,14 @@ module Tzispa
|
|
23
25
|
# evaluation is deferred until the body is read with #each.
|
24
26
|
def body(value = nil, &block)
|
25
27
|
if block_given?
|
26
|
-
def block.each
|
28
|
+
def block.each
|
29
|
+
yield(call)
|
30
|
+
end
|
27
31
|
response.body = block
|
28
32
|
elsif value
|
29
|
-
headers.delete 'Content-Length' unless request.head? ||
|
33
|
+
headers.delete 'Content-Length' unless request.head? ||
|
34
|
+
value.is_a?(Rack::File) ||
|
35
|
+
value.is_a?(Stream)
|
30
36
|
response.body = value
|
31
37
|
else
|
32
38
|
response.body
|
@@ -42,14 +48,7 @@ module Tzispa
|
|
42
48
|
|
43
49
|
# Halt processing and redirect to the URI provided.
|
44
50
|
def redirect(uri, absolute, *args)
|
45
|
-
|
46
|
-
status 303
|
47
|
-
else
|
48
|
-
status 302
|
49
|
-
end
|
50
|
-
|
51
|
-
# According to RFC 2616 section 14.30, "the field value consists of a
|
52
|
-
# single absolute URI"
|
51
|
+
status(request.allowed_http_version? && request.get? ? 303 : 302)
|
53
52
|
response['Location'] = uri(uri.to_s, absolute)
|
54
53
|
halt(*args)
|
55
54
|
end
|
@@ -61,27 +60,30 @@ module Tzispa
|
|
61
60
|
halt(*args)
|
62
61
|
end
|
63
62
|
|
64
|
-
|
65
63
|
# Generates the absolute URI for a given path in the app.
|
66
64
|
# Takes Rack routers and reverse proxies into account.
|
67
65
|
def uri(addr = nil, absolute = true)
|
68
|
-
return addr if addr
|
66
|
+
return addr if addr.match?(/\A[A-z][A-z0-9\+\.\-]*:/)
|
69
67
|
uri = [host = String.new]
|
70
|
-
if absolute
|
71
|
-
host << "http#{'s' if request.secure?}://"
|
72
|
-
if request.forwarded? or request.port != (request.secure? ? 443 : 80)
|
73
|
-
host << request.host_with_port
|
74
|
-
else
|
75
|
-
host << request.host
|
76
|
-
end
|
77
|
-
end
|
68
|
+
host << uri_host if absolute
|
78
69
|
uri << (addr ? addr : request.path_info).to_s
|
79
70
|
File.join uri
|
80
71
|
end
|
81
72
|
|
73
|
+
def uri_host
|
74
|
+
String.new.tap do |host|
|
75
|
+
host << "http#{'s' if request.secure?}://"
|
76
|
+
host << (uri_port? ? request.host_with_port : request.host)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def uri_port?
|
81
|
+
request.forwarded? || request.port != (request.secure? ? 443 : 80)
|
82
|
+
end
|
83
|
+
|
82
84
|
# Halt processing and return the error status provided.
|
83
|
-
def error(code, body = nil)
|
84
|
-
|
85
|
+
def error(code = 500, body = nil)
|
86
|
+
body = code.to_str if code.respond_to? :to_str
|
85
87
|
response.body = body unless body.nil?
|
86
88
|
halt code
|
87
89
|
end
|
@@ -95,7 +97,7 @@ module Tzispa
|
|
95
97
|
def unauthorized(body = nil)
|
96
98
|
error 401, body
|
97
99
|
end
|
98
|
-
|
100
|
+
alias not_authorized unauthorized
|
99
101
|
|
100
102
|
# Set multiple response headers with Hash.
|
101
103
|
def headers(hash = nil)
|
@@ -106,55 +108,17 @@ module Tzispa
|
|
106
108
|
# Set the Content-Type of the response body given a media type or file
|
107
109
|
# extension.
|
108
110
|
def content_type(type = nil, params = {})
|
109
|
-
return response
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
mime_type = mime_type.dup
|
114
|
-
unless params.include? :charset
|
115
|
-
params[:charset] = params.delete('charset') || config.default_encoding
|
116
|
-
end
|
117
|
-
params.delete :charset if mime_type.include? 'charset'
|
118
|
-
unless params.empty?
|
119
|
-
mime_type << (mime_type.include?(';') ? ', ' : ';')
|
120
|
-
mime_type << params.map do |key, val|
|
121
|
-
val = val.inspect if val =~ /[";,]/
|
122
|
-
"#{key}=#{val}"
|
123
|
-
end.join(', ')
|
124
|
-
end
|
125
|
-
response['Content-Type'] = mime_type
|
126
|
-
end
|
127
|
-
|
128
|
-
def attachment!(filename = nil, disposition = 'attachment')
|
129
|
-
content_disposition = disposition.to_s
|
130
|
-
content_disposition += "; filename=\"#{filename}\"; filename*=UTF-8''#{URI.escape(filename)}" if !filename.nil?
|
131
|
-
response['Content-Disposition'] = content_disposition
|
111
|
+
return if response.drop_content_info?
|
112
|
+
ct = Tzispa::Helpers::Services::ContentType.new(response,
|
113
|
+
config.default_encoding)
|
114
|
+
ct.header(type, params)
|
132
115
|
end
|
133
116
|
|
134
117
|
def send_file(path, opts = {})
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
disposition = opts[:disposition]
|
141
|
-
filename = opts[:filename]
|
142
|
-
disposition = 'attachment' if disposition.nil? and filename
|
143
|
-
filename = path if filename.nil?
|
144
|
-
|
145
|
-
attachment! filename, disposition
|
146
|
-
last_modified opts[:last_modified] if opts[:last_modified]
|
147
|
-
|
148
|
-
file = Rack::File.new(Dir.pwd)
|
149
|
-
result = file.serving(request, path)
|
150
|
-
|
151
|
-
result[1].each { |k,v| response.headers[k] ||= v }
|
152
|
-
response.headers['Content-Length'] = result[1]['Content-Length']
|
153
|
-
response.status = result[0]
|
154
|
-
response.body = result[2]
|
155
|
-
rescue
|
156
|
-
not_found 'Fichero no encontrado'
|
157
|
-
end
|
118
|
+
not_found unless ::File.exist? path
|
119
|
+
file = Rack::File.new(Dir.pwd)
|
120
|
+
fss = Tzispa::Helpers::Services::SendFile.new response, path, opts
|
121
|
+
fss.send file.serving(request, path)
|
158
122
|
end
|
159
123
|
|
160
124
|
# Sugar for redirect (example: redirect back)
|
@@ -192,12 +156,16 @@ module Tzispa
|
|
192
156
|
response.status == 404
|
193
157
|
end
|
194
158
|
|
159
|
+
def error_500(str)
|
160
|
+
500.tap { |_code| response.body = str if str }
|
161
|
+
end
|
195
162
|
|
196
163
|
class NotFound < NameError #:nodoc:
|
197
|
-
def http_status
|
164
|
+
def http_status
|
165
|
+
404
|
166
|
+
end
|
198
167
|
end
|
199
168
|
|
200
|
-
|
201
169
|
end
|
202
170
|
end
|
203
171
|
end
|
@@ -6,57 +6,46 @@ module Tzispa
|
|
6
6
|
module Helpers
|
7
7
|
module Security
|
8
8
|
|
9
|
-
|
10
9
|
def secret(length)
|
11
|
-
alfanb = (['!', '"', '·', '$', '%', '&', '/', '(', ')', '=',
|
12
|
-
|
13
|
-
|
10
|
+
alfanb = (['!', '"', '·', '$', '%', '&', '/', '(', ')', '=',
|
11
|
+
'?', '+', '@', '#', ',', '.', '-', ';', ':', '_',
|
12
|
+
'[', ']', '>', '<', '*'] <<
|
13
|
+
[('a'..'z'), ('0'..'9'), ('A'..'Z')].map(&:to_a)).flatten
|
14
14
|
(0...length).map { alfanb[rand(alfanb.length)] }.join
|
15
15
|
end
|
16
16
|
|
17
17
|
def uuid
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
rand(0..0x0fff) | 0x4000,
|
28
|
-
|
29
|
-
# 16 bits, 8 bits for "clk_seq_hi_res",
|
30
|
-
# 8 bits for "clk_seq_low",
|
31
|
-
# two most significant bits holds zero and one for variant DCE1.1
|
32
|
-
rand(0..0x3fff) | 0x8000,
|
33
|
-
|
34
|
-
# 48 bits for "node"
|
35
|
-
rand(0..0xffff), rand(0..0xffff), rand(0..0xffff)
|
36
|
-
)
|
18
|
+
format('%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
|
19
|
+
rand(0..0xffff),
|
20
|
+
rand(0..0xffff),
|
21
|
+
rand(0..0xffff),
|
22
|
+
rand(0..0x0fff) | 0x4000,
|
23
|
+
rand(0..0x3fff) | 0x8000,
|
24
|
+
rand(0..0xffff),
|
25
|
+
rand(0..0xffff),
|
26
|
+
rand(0..0xffff))
|
37
27
|
end
|
38
28
|
|
39
|
-
def sign_array(astr, salt=nil)
|
40
|
-
sign
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
29
|
+
def sign_array(astr, salt = nil)
|
30
|
+
sign = String.new
|
31
|
+
i = 0
|
32
|
+
astr.each do |s|
|
33
|
+
i += 1
|
34
|
+
sign << "#{'_' * i}#{s}"
|
35
|
+
end
|
45
36
|
sign << "**#{salt}"
|
46
37
|
Digest::SHA1.hexdigest sign
|
47
38
|
end
|
48
39
|
|
49
40
|
def hash_password(password, salt)
|
50
|
-
Digest::MD5
|
41
|
+
Digest::MD5.hexdigest "#{password}::#{salt}"
|
51
42
|
end
|
52
43
|
|
53
44
|
def hash_password?(hashed, pwd, salt)
|
54
45
|
hashed == hash_password(pwd, salt)
|
55
46
|
end
|
56
47
|
|
57
|
-
|
58
48
|
class Identity
|
59
|
-
|
60
49
|
attr_reader :id, :token
|
61
50
|
|
62
51
|
def initialize(id, secret)
|
@@ -68,15 +57,11 @@ module Tzispa
|
|
68
57
|
@token == Identity.generate_token(@id, secret)
|
69
58
|
end
|
70
59
|
|
71
|
-
private
|
72
|
-
|
73
60
|
def self.generate_token(value, salt)
|
74
61
|
Digest::SHA1.hexdigest "___#{value}_#{salt}__token__"
|
75
62
|
end
|
76
|
-
|
77
63
|
end
|
78
64
|
|
79
|
-
|
80
65
|
end
|
81
66
|
end
|
82
67
|
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'uri'
|
4
|
+
require 'tzispa/helpers/mime'
|
5
|
+
|
6
|
+
module Tzispa
|
7
|
+
module Helpers
|
8
|
+
module Services
|
9
|
+
|
10
|
+
class ContentType
|
11
|
+
include Tzispa::Helpers::Mime
|
12
|
+
|
13
|
+
attr_reader :response, :default_encoding
|
14
|
+
|
15
|
+
def initialize(response, default_encoding = nil)
|
16
|
+
@response = response
|
17
|
+
@default_encoding = default_encoding
|
18
|
+
end
|
19
|
+
|
20
|
+
# Set the Content-Type of the response body given a media type or file
|
21
|
+
# extension.
|
22
|
+
def header(type = nil, params = {})
|
23
|
+
return response['Content-Type'] unless type || params[:default]
|
24
|
+
default = params.delete :default
|
25
|
+
mime = mime_type(type) || default
|
26
|
+
raise "Unknown media type: #{type}" unless mime
|
27
|
+
params = charset mime, params
|
28
|
+
build mime.dup, params
|
29
|
+
end
|
30
|
+
|
31
|
+
def charset(mime, params)
|
32
|
+
unless params.include?(:charset) || mime.include?('charset')
|
33
|
+
params[:charset] = params.delete('charset') || default_encoding
|
34
|
+
end
|
35
|
+
params.delete :charset if mime.include? 'charset'
|
36
|
+
params
|
37
|
+
end
|
38
|
+
|
39
|
+
def file(type, extension = nil)
|
40
|
+
return unless response['Content-Type']
|
41
|
+
header type || extension,
|
42
|
+
default: 'application/octet-stream'
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def build(mime, params)
|
48
|
+
mime if params.empty?
|
49
|
+
mime << (mime.include?(';') ? ', ' : ';')
|
50
|
+
mime << params.select { |_, val| val&.match?(/[";,]/) }
|
51
|
+
.map do |key, val|
|
52
|
+
"#{key}=#{val.inspect}"
|
53
|
+
end.join(', ')
|
54
|
+
response['Content-Type'] = mime
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Tzispa
|
4
|
+
module Helpers
|
5
|
+
module Services
|
6
|
+
|
7
|
+
class ErrorView
|
8
|
+
attr_reader :exception
|
9
|
+
|
10
|
+
def initialize(exception)
|
11
|
+
@exception = exception
|
12
|
+
end
|
13
|
+
|
14
|
+
def error_header
|
15
|
+
"<h1>#{exception.class.name}</h1><h3>#{exception.message}</h3>"
|
16
|
+
end
|
17
|
+
|
18
|
+
def error_backtrace_list
|
19
|
+
return unless exception.respond_to?(:backtrace) && exception.backtrace
|
20
|
+
String.new.tap do |str|
|
21
|
+
str << '<ol>'
|
22
|
+
str << exception.backtrace.map { |trace| "<li>#{trace}</li>\n" }.join
|
23
|
+
str << '</ol>'
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def error_backtrace_log
|
28
|
+
return unless exception.respond_to?(:backtrace) && exception.backtrace
|
29
|
+
String.new.tap do |str|
|
30
|
+
str << "#{exception.class.name}: #{exception}:\n"
|
31
|
+
str << exception.backtrace.join("\n")
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'uri'
|
4
|
+
|
5
|
+
module Tzispa
|
6
|
+
module Helpers
|
7
|
+
module Services
|
8
|
+
|
9
|
+
class SendFile
|
10
|
+
attr_reader :response, :opts, :path
|
11
|
+
|
12
|
+
def initialize(response, path, opts)
|
13
|
+
@response = response
|
14
|
+
@opts = opts
|
15
|
+
@path = path
|
16
|
+
end
|
17
|
+
|
18
|
+
def content_disposition(filename = nil, disposition = 'attachment')
|
19
|
+
disposition = String.new << disposition.to_s
|
20
|
+
if filename
|
21
|
+
escaped = URI.escape(filename)
|
22
|
+
disposition << "; filename=\"#{escaped}\""
|
23
|
+
disposition << "; filename*=UTF-8''#{escaped}"
|
24
|
+
end
|
25
|
+
response['Content-Disposition'] = disposition
|
26
|
+
end
|
27
|
+
|
28
|
+
def send(result)
|
29
|
+
prepare
|
30
|
+
response.status = result[0]
|
31
|
+
if response.status.between? 200, 299
|
32
|
+
headers_set result[1]
|
33
|
+
response.body = result[2]
|
34
|
+
end
|
35
|
+
response
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def prepare
|
41
|
+
content_headers
|
42
|
+
disposition = opts[:disposition]
|
43
|
+
filename = opts[:filename]
|
44
|
+
disposition = 'attachment' if disposition.nil? && filename
|
45
|
+
filename = path if filename.nil?
|
46
|
+
content_disposition filename, disposition
|
47
|
+
end
|
48
|
+
|
49
|
+
def headers_set(headers)
|
50
|
+
headers.each { |k, v| response.headers[k] ||= v }
|
51
|
+
response.headers['Content-Length'] = headers['Content-Length']
|
52
|
+
response.no_cache.cache_private if opts[:no_cache]
|
53
|
+
end
|
54
|
+
|
55
|
+
def content_headers
|
56
|
+
ct = Tzispa::Helpers::Services::ContentType.new response
|
57
|
+
ct.file opts[:type], opts[:extension]
|
58
|
+
last_modified opts[:last_modified] if opts[:last_modified]
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'securerandom'
|
4
|
+
require 'tzispa/helpers/session_flash_bag'
|
5
|
+
|
6
|
+
module Tzispa
|
7
|
+
module Helpers
|
8
|
+
module Session
|
9
|
+
|
10
|
+
SESSION_LAST_ACCESS = :__last_access
|
11
|
+
SESSION_ID = :__session_id
|
12
|
+
SESSION_AUTH_USER = :__auth__user
|
13
|
+
GLOBAL_MESSAGE_FLASH = :__global_message_flash
|
14
|
+
|
15
|
+
def init_session
|
16
|
+
generate_session_id if config&.sessions&.enabled && !session?
|
17
|
+
end
|
18
|
+
|
19
|
+
def set_last_access
|
20
|
+
session[SESSION_LAST_ACCESS] = Time.now.utc.iso8601
|
21
|
+
end
|
22
|
+
|
23
|
+
def last_access
|
24
|
+
session[SESSION_LAST_ACCESS]
|
25
|
+
end
|
26
|
+
|
27
|
+
def flash
|
28
|
+
@flash ||= SessionFlashBag.new(session, GLOBAL_MESSAGE_FLASH)
|
29
|
+
end
|
30
|
+
|
31
|
+
def session?
|
32
|
+
!session[SESSION_ID].nil? && (session[SESSION_ID] == session.id)
|
33
|
+
end
|
34
|
+
|
35
|
+
def logged?
|
36
|
+
session? && login
|
37
|
+
end
|
38
|
+
|
39
|
+
def login=(user)
|
40
|
+
session[SESSION_AUTH_USER] = user unless user.nil?
|
41
|
+
end
|
42
|
+
|
43
|
+
def login
|
44
|
+
session[SESSION_AUTH_USER]
|
45
|
+
end
|
46
|
+
|
47
|
+
def logout
|
48
|
+
session.delete(SESSION_AUTH_USER)
|
49
|
+
end
|
50
|
+
|
51
|
+
def generate_session_id
|
52
|
+
SecureRandom.uuid.tap do |uuid|
|
53
|
+
session.id = uuid
|
54
|
+
session[SESSION_ID] = uuid
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'forwardable'
|
4
|
+
require 'json'
|
5
|
+
|
6
|
+
module Tzispa
|
7
|
+
module Helpers
|
8
|
+
module Session
|
9
|
+
|
10
|
+
class SessionFlashBag
|
11
|
+
extend Forwardable
|
12
|
+
|
13
|
+
def_delegators :@bag, :count, :length, :size, :each
|
14
|
+
|
15
|
+
SESSION_FLASH_BAG = :__flash_bag
|
16
|
+
|
17
|
+
def initialize(session, key)
|
18
|
+
@session = session
|
19
|
+
@session_key = "#{SESSION_FLASH_BAG}_#{key}".to_sym
|
20
|
+
load!
|
21
|
+
end
|
22
|
+
|
23
|
+
def <<(value)
|
24
|
+
return unless value
|
25
|
+
bag << value
|
26
|
+
store
|
27
|
+
end
|
28
|
+
|
29
|
+
def pop
|
30
|
+
value = bag.pop
|
31
|
+
store
|
32
|
+
value
|
33
|
+
end
|
34
|
+
|
35
|
+
def pop_all
|
36
|
+
empty!
|
37
|
+
bag
|
38
|
+
end
|
39
|
+
|
40
|
+
def push(value)
|
41
|
+
bag.push value
|
42
|
+
store
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
attr_reader :bag, :session, :session_key
|
48
|
+
|
49
|
+
def load!
|
50
|
+
@bag = session[session_key] ? JSON.parse(session[session_key]) : []
|
51
|
+
end
|
52
|
+
|
53
|
+
def store
|
54
|
+
session[session_key] = bag.to_json
|
55
|
+
end
|
56
|
+
|
57
|
+
def empty!
|
58
|
+
session[session_key] = []
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require_relative 'requirer'
|
2
4
|
|
3
5
|
module Tzispa
|
@@ -17,9 +19,7 @@ module Tzispa
|
|
17
19
|
self.class.sign_valid? self
|
18
20
|
end
|
19
21
|
|
20
|
-
|
21
22
|
module ClassMethods
|
22
|
-
|
23
23
|
def sign_required!(&block)
|
24
24
|
required(:router_params, :sign, &block)
|
25
25
|
end
|
@@ -31,7 +31,6 @@ module Tzispa
|
|
31
31
|
def sign_valid?(obj)
|
32
32
|
required_valid? :router_params, :sign, obj
|
33
33
|
end
|
34
|
-
|
35
34
|
end
|
36
35
|
|
37
36
|
end
|
data/lib/tzispa/helpers/text.rb
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
require 'date'
|
4
4
|
require 'bigdecimal'
|
5
5
|
require 'i18n'
|
6
|
-
require
|
6
|
+
require 'unicode_utils'
|
7
7
|
require 'cgi/util'
|
8
8
|
|
9
9
|
module Tzispa
|
@@ -11,13 +11,11 @@ module Tzispa
|
|
11
11
|
module Text
|
12
12
|
|
13
13
|
def remove_words(sentence, removable)
|
14
|
-
sentence.split.delete_if{|x| removable.include?
|
14
|
+
sentence.split.delete_if { |x| removable.include? UnicodeUtils.downcase(x) }.join(' ')
|
15
15
|
end
|
16
16
|
|
17
17
|
def remove_phrases(text, removable)
|
18
|
-
removable.each { |phrase|
|
19
|
-
text.slice! phrase
|
20
|
-
}
|
18
|
+
removable.each { |phrase| text.slice! phrase }
|
21
19
|
text
|
22
20
|
end
|
23
21
|
|
@@ -26,68 +24,67 @@ module Tzispa
|
|
26
24
|
end
|
27
25
|
|
28
26
|
def synonymize(sentence, synonyms)
|
29
|
-
sentence.gsub(/[[:alnum:]]+/)
|
27
|
+
sentence.gsub(/[[:alnum:]]+/) do |word|
|
30
28
|
dwword = UnicodeUtils.downcase word
|
31
|
-
synonyms.
|
32
|
-
|
29
|
+
synonyms.key?(dwword) ? synonyms[dwword] : word
|
30
|
+
end
|
33
31
|
end
|
34
32
|
|
35
33
|
def strip_to_nil(str, transform = nil)
|
36
|
-
sstr = str.strip if str
|
34
|
+
sstr = str.strip if str && !str.strip.empty?
|
37
35
|
case transform
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
36
|
+
when :upcase then
|
37
|
+
UnicodeUtils.upcase(sstr)
|
38
|
+
when :downcase then
|
39
|
+
UnicodeUtils.downcase(sstr)
|
40
|
+
when :titlecase then
|
41
|
+
UnicodeUtils.titlecase(sstr)
|
42
|
+
else
|
43
|
+
sstr
|
45
44
|
end
|
46
45
|
end
|
47
46
|
|
48
47
|
def html_unscape(str)
|
49
|
-
CGI
|
48
|
+
CGI.unescapeHTML(str.strip) if str && !str.strip.empty?
|
50
49
|
end
|
51
50
|
|
52
|
-
def split_to_array(str, separator=';')
|
53
|
-
str
|
51
|
+
def split_to_array(str, separator = ';')
|
52
|
+
str&.split(separator)
|
54
53
|
end
|
55
54
|
|
56
55
|
def join_to_nil(ary, separator)
|
57
|
-
ary.join(separator) if ary
|
56
|
+
ary.join(separator) if ary && !ary.empty?
|
58
57
|
end
|
59
58
|
|
60
|
-
def str_to_bool(str, strue=nil)
|
59
|
+
def str_to_bool(str, strue = nil)
|
61
60
|
strue ? (strue == str) : (str == 'yes' || str == 'true')
|
62
61
|
end
|
63
62
|
|
64
|
-
def str_to_date(str, format=nil)
|
63
|
+
def str_to_date(str, format = nil)
|
65
64
|
str = strip_to_nil str
|
66
65
|
Date.strptime(str, format || I18n.t('date.formats.default')) if str
|
67
66
|
end
|
68
67
|
|
69
|
-
def str_to_datetime(str, format=nil)
|
68
|
+
def str_to_datetime(str, format = nil)
|
70
69
|
str = strip_to_nil str
|
71
70
|
DateTime.strptime(str, format || I18n.t('datetime.formats.default'))
|
72
71
|
end
|
73
72
|
|
74
|
-
def str_time_ellapsed(t_start, t_end=nil)
|
73
|
+
def str_time_ellapsed(t_start, t_end = nil)
|
75
74
|
elapsed = (t_end || Time.now) - t_start
|
76
75
|
seconds = elapsed % 60
|
77
76
|
minutes = (elapsed / 60) % 60
|
78
77
|
hours = elapsed / (60 * 60)
|
79
|
-
format(
|
78
|
+
format('%02d:%02d:%02d', hours, minutes, seconds)
|
80
79
|
end
|
81
80
|
|
82
81
|
def str_to_amount(str, options = {})
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
BigDecimal.new(str).round(precision).to_s('F')
|
90
|
-
end
|
82
|
+
return unless !str || str.strip.empty?
|
83
|
+
separator = options.fetch(:separator, I18n.t('number.currency.format.separator'))
|
84
|
+
precision = options.fetch(:precision, I18n.t('number.currency.format.precision'))
|
85
|
+
str = str.gsub(Regexp.new("[^\\d\\#{separator}\\-]"), '')
|
86
|
+
str = str.gsub(separator, '.') if separator != '.'
|
87
|
+
BigDecimal.new(str).round(precision).to_s('F')
|
91
88
|
end
|
92
89
|
|
93
90
|
def amount(number, options = {})
|
@@ -106,30 +103,34 @@ module Tzispa
|
|
106
103
|
separator = options.fetch(:separator, I18n.t('number.currency.format.separator'))
|
107
104
|
delimiter = options.fetch(:delimiter, I18n.t('number.currency.format.delimiter')).to_s
|
108
105
|
minimum_precision = options[:minimum_precision] || 0
|
109
|
-
str = number.is_a?(BigDecimal)
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
106
|
+
str = if number.is_a?(BigDecimal)
|
107
|
+
number.to_s('F').sub(/\.0+\z/, '')
|
108
|
+
else
|
109
|
+
number.to_s.sub(/\.0+\z/, '')
|
110
|
+
end
|
111
|
+
smatch = str.match(/\A(\-?)(\d+)(?:\.(\d+))?\z/)
|
112
|
+
raise "Could not parse number: #{number}" unless smatch
|
113
|
+
sign = smatch[1]
|
114
|
+
integer = smatch[2]
|
115
|
+
fraction = (smatch[3] || '')
|
114
116
|
|
115
117
|
if options[:maximum_precision]
|
116
118
|
fraction = fraction[0, options[:maximum_precision]] if options[:maximum_precision]
|
117
119
|
end
|
118
120
|
|
119
|
-
|
120
|
-
if fraction.length > 0 && minimum_precision > 0
|
121
|
+
if fraction.positive? && minimum_precision.positive?
|
121
122
|
fraction = "#{fraction}#{'0' * [0, minimum_precision - fraction.length].max}"
|
122
|
-
elsif minimum_precision
|
123
|
+
elsif minimum_precision.zero? && !fraction.empty? && fraction.to_i.zero?
|
123
124
|
fraction = ''
|
124
125
|
end
|
125
126
|
|
126
|
-
#
|
127
|
+
# add a delimiter to every thousands place in the number
|
127
128
|
integer_size = integer.size
|
128
|
-
(1..((integer_size-1) / 3)).each {|x| integer[integer_size-x*3,0] = delimiter}
|
129
|
+
(1..((integer_size - 1) / 3)).each { |x| integer[integer_size - x * 3, 0] = delimiter }
|
129
130
|
str = integer.chomp(delimiter)
|
130
131
|
|
131
132
|
# add fraction
|
132
|
-
str << "#{separator}#{fraction}"
|
133
|
+
str << "#{separator}#{fraction}" unless fraction.empty?
|
133
134
|
|
134
135
|
# restore sign
|
135
136
|
str = "#{sign}#{str}"
|
@@ -145,22 +146,26 @@ module Tzispa
|
|
145
146
|
end
|
146
147
|
|
147
148
|
def money_amount(number, options = {})
|
148
|
-
amount(number, options.merge(:
|
149
|
+
amount(number, options.merge(unit: I18n.t('number.currency.format.unit'),
|
150
|
+
nil_as_dash: false,
|
151
|
+
precision: I18n.t('number.currency.format.precision'),
|
152
|
+
minimum_precision: 0))
|
149
153
|
end
|
150
154
|
|
151
155
|
def price_amount(number, options = {})
|
152
|
-
amount(number, options.merge(:
|
156
|
+
amount(number, options.merge(nil_as_dash: false,
|
157
|
+
precision: I18n.t('number.currency.format.precision'),
|
158
|
+
minimum_precision: 0))
|
153
159
|
end
|
154
160
|
|
155
161
|
def starinizer(rating, star_value, max_stars)
|
156
|
-
|
162
|
+
{}.tap do |stars|
|
157
163
|
stars[:full] = rating / star_value
|
158
164
|
stars[:half] = rating % star_value
|
159
165
|
stars[:o] = max_stars - stars[:full] - stars[:half]
|
160
|
-
|
166
|
+
end
|
161
167
|
end
|
162
168
|
|
163
|
-
|
164
169
|
end
|
165
170
|
end
|
166
171
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tzispa_helpers
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Juan Antonio Piñero
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-03-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: i18n
|
@@ -64,7 +64,6 @@ files:
|
|
64
64
|
- lib/tzispa/helpers.rb
|
65
65
|
- lib/tzispa/helpers/date_time.rb
|
66
66
|
- lib/tzispa/helpers/error_view.rb
|
67
|
-
- lib/tzispa/helpers/hash_trans.rb
|
68
67
|
- lib/tzispa/helpers/html.rb
|
69
68
|
- lib/tzispa/helpers/mime.rb
|
70
69
|
- lib/tzispa/helpers/pattern.rb
|
@@ -73,6 +72,11 @@ files:
|
|
73
72
|
- lib/tzispa/helpers/requirer.rb
|
74
73
|
- lib/tzispa/helpers/response.rb
|
75
74
|
- lib/tzispa/helpers/security.rb
|
75
|
+
- lib/tzispa/helpers/services/content_type.rb
|
76
|
+
- lib/tzispa/helpers/services/error_view.rb
|
77
|
+
- lib/tzispa/helpers/services/send_file.rb
|
78
|
+
- lib/tzispa/helpers/session.rb
|
79
|
+
- lib/tzispa/helpers/session_flash_bag.rb
|
76
80
|
- lib/tzispa/helpers/sign_requirer.rb
|
77
81
|
- lib/tzispa/helpers/text.rb
|
78
82
|
- lib/tzispa/helpers/version.rb
|
@@ -1,18 +0,0 @@
|
|
1
|
-
module Tzispa
|
2
|
-
module Helpers
|
3
|
-
module HashTrans
|
4
|
-
|
5
|
-
def hash_fussion!(hash, fussion_keys={})
|
6
|
-
hash.keys.each { |key|
|
7
|
-
if fussion_keys.has_key?(key)
|
8
|
-
hash[fussion_keys[key]] ?
|
9
|
-
hash[fussion_keys[key]] += hash[key] :
|
10
|
-
hash[fussion_keys[key]] = hash[key]
|
11
|
-
hash.delete(key)
|
12
|
-
end
|
13
|
-
} unless fussion_keys.empty?
|
14
|
-
end
|
15
|
-
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|