nifty-utils 1.0.5 → 1.1.7
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/lib/nifty/utils/active_record/default_value.rb +56 -0
- data/lib/nifty/utils/active_record/inquirer.rb +40 -0
- data/lib/nifty/utils/active_record/random_string.rb +77 -0
- data/lib/nifty/utils/auto_attribute_permit.rb +70 -0
- data/lib/nifty/utils/extensions/core.rb +2 -1
- data/lib/nifty/utils/extensions/object.rb +9 -0
- data/lib/nifty/utils/extensions/string.rb +10 -6
- data/lib/nifty/utils/http.rb +78 -0
- data/lib/nifty/utils/networks.rb +28 -0
- data/lib/nifty/utils/railtie.rb +12 -7
- data/lib/nifty/utils/until_with_max_attempts.rb +45 -0
- data/lib/nifty/utils/version.rb +1 -1
- data/lib/nifty/utils/view_helpers.rb +60 -11
- data/locales/en.yml +4 -0
- metadata +18 -10
- data/lib/nifty/utils/active_record.rb +0 -38
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0f43ab7bf985adc936f4f3d5af7d9aeed18f5874
|
4
|
+
data.tar.gz: 8f219e2ad9b79506674ab44989fd62c281d8b933
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 01e12d189131662b24b3b31e0c17eb94d339b68fd419e8eaecb4d6a43551d369297cbf3d7c45cd6d58b65898e15b399d0be54a09c52d87436eab365be939e8bf
|
7
|
+
data.tar.gz: fe8b782a9f0538d2764b954b4fdc25ba23b5f2dee681859d801745cbbca1b1b45389ea9dc1c5f11b9c96631d8291fb5de237215f60a35fedeec78306d6c4a9d3
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module Nifty
|
2
|
+
module Utils
|
3
|
+
module ActiveRecord
|
4
|
+
module DefaultValue
|
5
|
+
|
6
|
+
def self.included(base)
|
7
|
+
base.extend ClassMethods
|
8
|
+
end
|
9
|
+
|
10
|
+
module ClassMethods
|
11
|
+
|
12
|
+
def has_default_values?
|
13
|
+
false
|
14
|
+
end
|
15
|
+
|
16
|
+
def default_value(field, block, options = {})
|
17
|
+
self.send :include, ModelExtensions unless self.has_default_values?
|
18
|
+
self.default_value_definitions[field] = options.merge(:block => block)
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
module ModelExtensions
|
24
|
+
|
25
|
+
def self.included(base)
|
26
|
+
base.extend ClassMethods
|
27
|
+
base.before_validation :_set_default_values
|
28
|
+
end
|
29
|
+
|
30
|
+
def _set_default_values
|
31
|
+
self.class.default_value_definitions.each do |field, opts|
|
32
|
+
if self.send(field).blank?
|
33
|
+
proposed_value = self.instance_exec(&opts[:block])
|
34
|
+
self.send("#{field}=", proposed_value)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
module ClassMethods
|
40
|
+
|
41
|
+
def default_value_definitions
|
42
|
+
@default_value_definitions ||= {}
|
43
|
+
end
|
44
|
+
|
45
|
+
def has_default_values?
|
46
|
+
true
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Nifty
|
2
|
+
module Utils
|
3
|
+
module ActiveRecord
|
4
|
+
module Inquirer
|
5
|
+
|
6
|
+
#:nodoc:
|
7
|
+
def self.included(base)
|
8
|
+
base.extend ClassMethods
|
9
|
+
end
|
10
|
+
|
11
|
+
module ClassMethods
|
12
|
+
|
13
|
+
# Allows you to automatically create inquiry methods for string field. For example, if you have
|
14
|
+
# an Order model which has a status field containing 'approved' or 'delivered' you may wish to
|
15
|
+
# have a #approved? or #delivered? method on the model.
|
16
|
+
#
|
17
|
+
# class Order < ActiveRecord::Baser
|
18
|
+
# STATUSES = ['approved', 'delivered']
|
19
|
+
# inquirer :status, *STATUSES
|
20
|
+
# end
|
21
|
+
#
|
22
|
+
# order = Order.new(:status => 'approved')
|
23
|
+
# order.approved? #=> true
|
24
|
+
# order.delivered? #=> false
|
25
|
+
#
|
26
|
+
#
|
27
|
+
def inquirer(field, *options)
|
28
|
+
options.each do |option|
|
29
|
+
define_method "#{option}?" do
|
30
|
+
self.read_attribute(field).to_s == option.to_s
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
require 'securerandom'
|
2
|
+
require 'nifty/utils/random_string'
|
3
|
+
|
4
|
+
module Nifty
|
5
|
+
module Utils
|
6
|
+
module ActiveRecord
|
7
|
+
module RandomString
|
8
|
+
|
9
|
+
def self.included(base)
|
10
|
+
base.extend ClassMethods
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.random_string(type, opts = {})
|
14
|
+
case type.to_sym
|
15
|
+
when :uuid
|
16
|
+
SecureRandom.uuid
|
17
|
+
when :chars
|
18
|
+
Nifty::Utils::RandomString.generate(opts)
|
19
|
+
else
|
20
|
+
SecureRandom.hex(opts[:length] || 24)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
module ClassMethods
|
25
|
+
|
26
|
+
def has_random_strings?
|
27
|
+
false
|
28
|
+
end
|
29
|
+
|
30
|
+
def random_string(field, options = {})
|
31
|
+
self.send :include, ModelExtensions unless self.has_random_strings?
|
32
|
+
self.random_string_fields[field] = options
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
module ModelExtensions
|
38
|
+
|
39
|
+
def self.included(base)
|
40
|
+
base.extend ClassMethods
|
41
|
+
base.before_validation :generate_random_strings
|
42
|
+
end
|
43
|
+
|
44
|
+
def generate_random_strings
|
45
|
+
self.class.random_string_fields.each do |field, opts|
|
46
|
+
if self.send(field).blank?
|
47
|
+
if opts[:unique]
|
48
|
+
until self.send(field)
|
49
|
+
proposed_string = RandomString.random_string(opts[:type], opts)
|
50
|
+
unless self.class.where(field => proposed_string).exists?
|
51
|
+
self.send("#{field}=", proposed_string)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
else
|
55
|
+
self.send("#{field}=", RandomString.random_string(opts[:type], opts))
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
module ClassMethods
|
62
|
+
|
63
|
+
def random_string_fields
|
64
|
+
@random_string_fields ||= {}
|
65
|
+
end
|
66
|
+
|
67
|
+
def has_random_strings?
|
68
|
+
true
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
module Nifty
|
2
|
+
module Utils
|
3
|
+
module AutoAttributePermit
|
4
|
+
|
5
|
+
def self.setup
|
6
|
+
ActionView::Helpers::FormBuilder.send :include, FormBuilderExtensions
|
7
|
+
ActionController::Parameters.send :include, StrongParameterExtensions
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.verifier
|
11
|
+
@verifier ||= ActiveSupport::MessageVerifier.new(Rails.application.secrets.secret_key_base)
|
12
|
+
end
|
13
|
+
|
14
|
+
module StrongParameterExtensions
|
15
|
+
def self.included(base)
|
16
|
+
base.class_eval do
|
17
|
+
alias_method_chain :permit, :auto_attribute_permit
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def permit_with_auto_attribute_permit(*filters)
|
22
|
+
if filters.delete(:auto)
|
23
|
+
fields = AutoAttributePermit.verifier.verify(self['permitted_fields'])
|
24
|
+
permit_without_auto_attribute_permit(*(fields | filters))
|
25
|
+
else
|
26
|
+
permit_without_auto_attribute_permit(*filters)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
module FormBuilderExtensions
|
32
|
+
def self.included(base)
|
33
|
+
base.class_eval do
|
34
|
+
alias_method_chain :label, :auto_attribute_permit
|
35
|
+
alias_method_chain :submit, :auto_attribute_permit
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def auto_permitted_attributes
|
40
|
+
@auto_permitted_attributes ||= []
|
41
|
+
end
|
42
|
+
|
43
|
+
def label_with_auto_attribute_permit(method, text = nil, options = {}, &block)
|
44
|
+
auto_permitted_attributes << method unless (text.is_a?(Hash) ? text : options)[:auto_permit] == false
|
45
|
+
label_without_auto_attribute_permit(method, text, options, &block)
|
46
|
+
end
|
47
|
+
|
48
|
+
def submit_with_auto_attribute_permit(value = nil, options = {})
|
49
|
+
value, options = nil, value if value.is_a?(Hash)
|
50
|
+
include_permit_field = options.delete(:include_auto_permit_field)
|
51
|
+
submit_button = submit_without_auto_attribute_permit(value, options)
|
52
|
+
unless include_permit_field == false
|
53
|
+
submit_button.safe_concat(self.auto_permitted_attributes_field)
|
54
|
+
else
|
55
|
+
submit_button
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def encoded_auto_permitted_attributes
|
60
|
+
AutoAttributePermit.verifier.generate(auto_permitted_attributes)
|
61
|
+
end
|
62
|
+
|
63
|
+
def auto_permitted_attributes_field
|
64
|
+
@template.hidden_field_tag("#{@object_name}[permitted_fields]", encoded_auto_permitted_attributes)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -1 +1,2 @@
|
|
1
|
-
require 'nifty/utils/extensions/
|
1
|
+
require 'nifty/utils/extensions/object'
|
2
|
+
require 'nifty/utils/extensions/string'
|
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'nifty/utils/random_string'
|
2
2
|
|
3
3
|
class String
|
4
|
-
|
4
|
+
|
5
5
|
def self.random(options = {})
|
6
6
|
Nifty::Utils::RandomString.generate(options)
|
7
7
|
end
|
@@ -9,17 +9,21 @@ class String
|
|
9
9
|
def ansi(code)
|
10
10
|
"\e[#{code.to_s}m#{self}\e[0m"
|
11
11
|
end
|
12
|
-
|
12
|
+
|
13
13
|
def red
|
14
14
|
self.ansi(31)
|
15
15
|
end
|
16
|
-
|
16
|
+
|
17
17
|
def green
|
18
18
|
self.ansi(32)
|
19
19
|
end
|
20
|
-
|
21
|
-
def
|
20
|
+
|
21
|
+
def yellow
|
22
22
|
self.ansi(33)
|
23
23
|
end
|
24
|
-
|
24
|
+
|
25
|
+
def blue
|
26
|
+
self.ansi(34)
|
27
|
+
end
|
28
|
+
|
25
29
|
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
require 'net/https'
|
2
|
+
require 'uri'
|
3
|
+
|
4
|
+
module Nifty
|
5
|
+
module Utils
|
6
|
+
module HTTP
|
7
|
+
|
8
|
+
def self.get(url, options = {})
|
9
|
+
request(Net::HTTP::Get, url, options)
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.post(url, options = {})
|
13
|
+
request(Net::HTTP::Post, url, options)
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.request(method, url, options = {})
|
17
|
+
options[:headers] ||= {}
|
18
|
+
uri = URI.parse(url)
|
19
|
+
request = method.new(uri.path.length == 0 ? "/" : uri.path)
|
20
|
+
options[:headers].each { |k,v| request.add_field k, v }
|
21
|
+
|
22
|
+
if options[:username]
|
23
|
+
request.basic_auth(options[:username], options[:password])
|
24
|
+
end
|
25
|
+
|
26
|
+
if options[:params].is_a?(Hash)
|
27
|
+
# If params has been provided, sent it them as form encoded values
|
28
|
+
request.set_form_data(options[:params])
|
29
|
+
|
30
|
+
elsif options[:json].is_a?(String)
|
31
|
+
# If we have a JSON string, set the content type and body to be the JSON
|
32
|
+
# data
|
33
|
+
request.add_field 'Content-Type', 'application/json'
|
34
|
+
request.body = options[:json]
|
35
|
+
end
|
36
|
+
|
37
|
+
if options[:user_agent]
|
38
|
+
request['User-Agent'] = options[:user_agent]
|
39
|
+
end
|
40
|
+
|
41
|
+
connection = Net::HTTP.new(uri.host, uri.port)
|
42
|
+
|
43
|
+
if uri.scheme == 'https'
|
44
|
+
connection.use_ssl = true
|
45
|
+
connection.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
46
|
+
end
|
47
|
+
|
48
|
+
begin
|
49
|
+
timeout = options[:timeout] || 60
|
50
|
+
Timeout.timeout(timeout) do
|
51
|
+
result = connection.request(request)
|
52
|
+
if result.content_type == 'application/json'
|
53
|
+
body = JSON.parse(result.body)
|
54
|
+
else
|
55
|
+
body = result.body
|
56
|
+
end
|
57
|
+
{
|
58
|
+
:code => result.code.to_i,
|
59
|
+
:type => result.content_type,
|
60
|
+
:body => body
|
61
|
+
}
|
62
|
+
end
|
63
|
+
rescue SocketError, Errno::ECONNRESET, EOFError, Errno::EINVAL => e
|
64
|
+
{
|
65
|
+
:code => -2,
|
66
|
+
:body => e.message
|
67
|
+
}
|
68
|
+
rescue Timeout::Error => e
|
69
|
+
{
|
70
|
+
:code => -1,
|
71
|
+
:body => "Timed out after #{timeout}s"
|
72
|
+
}
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'ipaddr'
|
2
|
+
|
3
|
+
module Nifty
|
4
|
+
module Utils
|
5
|
+
module Networks
|
6
|
+
|
7
|
+
def self.ip_in_networks?(ip, networks = [])
|
8
|
+
!!network_for_ip(networks, ip)
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.network_for_ip(networks, ip)
|
12
|
+
networks.each do |i|
|
13
|
+
if IPAddr.new(i).include?(ip)
|
14
|
+
return i
|
15
|
+
end
|
16
|
+
end
|
17
|
+
return nil
|
18
|
+
rescue ArgumentError => e
|
19
|
+
if e.message == 'invalid address'
|
20
|
+
return nil
|
21
|
+
else
|
22
|
+
raise
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
data/lib/nifty/utils/railtie.rb
CHANGED
@@ -1,23 +1,28 @@
|
|
1
1
|
module Nifty
|
2
2
|
module Utils
|
3
3
|
class Railtie < Rails::Railtie #:nodoc:
|
4
|
-
|
5
|
-
initializer 'nifty.utils.initialize' do
|
4
|
+
|
5
|
+
initializer 'nifty.utils.initialize' do |app|
|
6
|
+
Rails.application.config.i18n.load_path << File.expand_path(File.join('..', '..', '..', '..', 'locales', 'en.yml'), __FILE__)
|
6
7
|
|
7
8
|
# Load the Active Record extensions
|
8
9
|
ActiveSupport.on_load(:active_record) do
|
9
|
-
require 'nifty/utils/active_record'
|
10
|
-
::ActiveRecord::Base.send :include, Nifty::Utils::ActiveRecord
|
10
|
+
require 'nifty/utils/active_record/inquirer'
|
11
|
+
::ActiveRecord::Base.send :include, Nifty::Utils::ActiveRecord::Inquirer
|
12
|
+
require 'nifty/utils/active_record/random_string'
|
13
|
+
::ActiveRecord::Base.send :include, Nifty::Utils::ActiveRecord::RandomString
|
14
|
+
require 'nifty/utils/active_record/default_value'
|
15
|
+
::ActiveRecord::Base.send :include, Nifty::Utils::ActiveRecord::DefaultValue
|
11
16
|
end
|
12
|
-
|
17
|
+
|
13
18
|
# load the Action View helpers
|
14
19
|
ActiveSupport.on_load(:action_view) do
|
15
20
|
require 'nifty/utils/view_helpers'
|
16
21
|
ActionView::Base.send :include, Nifty::Utils::ViewHelpers
|
17
22
|
end
|
18
|
-
|
23
|
+
|
19
24
|
end
|
20
|
-
|
25
|
+
|
21
26
|
end
|
22
27
|
end
|
23
28
|
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Nifty
|
2
|
+
module Utils
|
3
|
+
module UntilWithMaxAttempts
|
4
|
+
|
5
|
+
#
|
6
|
+
# The exception which will be raised if the maximum number of attempts
|
7
|
+
# is reached.
|
8
|
+
#
|
9
|
+
class MaxAttemptsReached < StandardError; end
|
10
|
+
|
11
|
+
#
|
12
|
+
# Like a usual while block but with a maximum attempt counter. Can be used
|
13
|
+
# like this
|
14
|
+
#
|
15
|
+
# Attempts.until proc { job.completed? }, :attempts => 10, :gap => 5 do
|
16
|
+
# puts "Waiting for job to complete..."
|
17
|
+
# end
|
18
|
+
#
|
19
|
+
# The proc is the condition which will be evaluated, :attempts sets the
|
20
|
+
# maximum number of times it will wait before raising an exception and :gap
|
21
|
+
# is the length of time in seconds to wait between each check.
|
22
|
+
#
|
23
|
+
def self.until(condition, options = {}, &block)
|
24
|
+
options[:attempts] ||= 10
|
25
|
+
count = 0
|
26
|
+
until condition.call
|
27
|
+
|
28
|
+
if count == options[:attempts]
|
29
|
+
raise MaxAttemptsReached, "Maximum attempts reached (#{options[:attempts]}) without success"
|
30
|
+
end
|
31
|
+
|
32
|
+
yield
|
33
|
+
|
34
|
+
count += 1
|
35
|
+
|
36
|
+
if options[:gap] && count < options[:attempts]
|
37
|
+
sleep options[:gap]
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
data/lib/nifty/utils/version.rb
CHANGED
@@ -1,21 +1,24 @@
|
|
1
1
|
module Nifty
|
2
2
|
module Utils
|
3
3
|
module ViewHelpers
|
4
|
-
|
4
|
+
|
5
5
|
# Displays the full contents of the `flash` hash within an appropriate <div>
|
6
6
|
# element. The ID of the outputted div will be `flash-alert` where alert is the
|
7
|
-
# type of flash.
|
7
|
+
# type of flash.
|
8
8
|
#
|
9
|
-
#
|
10
|
-
def display_flash
|
11
|
-
|
12
|
-
|
9
|
+
# * <tt>:types</tt>: the names of flash messages to display with this helper
|
10
|
+
def display_flash(options = {})
|
11
|
+
options[:types] ||= [:alert, :warning, :notice]
|
12
|
+
options[:types].map do |key|
|
13
|
+
if flash[key]
|
14
|
+
content_tag :div, content_tag(:p, h(flash[key])), :id => "flash-#{key}", :class => "flashMessage flashMessage--#{key}"
|
15
|
+
end
|
13
16
|
end.join.html_safe
|
14
17
|
end
|
15
|
-
|
18
|
+
|
16
19
|
# Renders an `<img>` containing a link to the gravatar for the given e-mail address.
|
17
20
|
# Available options as follows:
|
18
|
-
#
|
21
|
+
#
|
19
22
|
# * <tt>:size</tt>: the size in pixels of the outputted gravatar. Defaults to 35.
|
20
23
|
# * <tt>:default</tt>: the gravatar to fallback to if the user has no gravatar
|
21
24
|
# (see gravatar for available options or pass a URL). Defaults to 'identicon'.
|
@@ -34,10 +37,10 @@ module Nifty
|
|
34
37
|
path = "/avatar.php?gravatar_id=#{Digest::MD5.hexdigest(email.to_s.downcase)}&rating=#{options[:rating]}&size=#{options[:size] * 2}&d=#{options[:default]}"
|
35
38
|
image_tag([host,path].join, :class => options[:class], :width => options[:size], :height => options[:size])
|
36
39
|
end
|
37
|
-
|
40
|
+
|
38
41
|
# Renders a tick or cross character based on the provided boolean. Additional options
|
39
42
|
# can be passed if needed.
|
40
|
-
#
|
43
|
+
#
|
41
44
|
# * <tt>:true_text</tt> - text to display next to a tick
|
42
45
|
# * <tt>:false_text</tt> - text to display next to a cross
|
43
46
|
def boolean_tag(bool, tip = nil, options = {})
|
@@ -46,7 +49,53 @@ module Nifty
|
|
46
49
|
false_text = " <b>#{options[:false_text]}</b>" if options[:false_text]
|
47
50
|
content_tag :span, (bool ? "<span class='true'>✔#{true_text}</span>" : "<span class='false'>✘#{false_text}</span>").html_safe, :class => "boolean", :title => tip
|
48
51
|
end
|
49
|
-
|
52
|
+
|
53
|
+
# Returns a URL to share some content on Twitter
|
54
|
+
#
|
55
|
+
# * <tt>:text</tt> - the text you wish to tweet
|
56
|
+
# * <tt>:url</tt> - the URL you want to tweet
|
57
|
+
def twitter_share_url(options = {})
|
58
|
+
"https://twitter.com/share?text=#{CGI.escape(options[:text])}&url=#{CGI.escape(options[:url])}"
|
59
|
+
end
|
60
|
+
|
61
|
+
# Returns a length of time in works (no I18N)
|
62
|
+
#
|
63
|
+
def length_of_time_in_words(seconds, options = {})
|
64
|
+
days = (seconds / 60 / 60 / 24).floor
|
65
|
+
hours = ((seconds / 60 / 60) - (days * 24)).floor
|
66
|
+
minutes = ((seconds / 60) - (days * 24 * 60) - (hours * 60)).floor
|
67
|
+
seconds = (seconds - (days * 24 * 60 * 60) - (hours * 60 * 60) - (minutes * 60)).floor
|
68
|
+
Array.new.tap do |s|
|
69
|
+
if options[:short]
|
70
|
+
s << "#{days}d" if days > 0
|
71
|
+
s << "#{hours}h" if hours > 0
|
72
|
+
s << "#{minutes}m" if minutes > 0
|
73
|
+
s << "#{seconds}s" if seconds > 0
|
74
|
+
else
|
75
|
+
s << pluralize(days, 'day') if days > 0
|
76
|
+
s << pluralize(hours, 'hour') if hours > 0
|
77
|
+
s << pluralize(minutes, 'minute') if minutes > 0
|
78
|
+
s << pluralize(seconds, 'second') if seconds > 0
|
79
|
+
end
|
80
|
+
end.join(options[:short] ? ' ' : ', ')
|
81
|
+
end
|
82
|
+
|
83
|
+
# Return an image path for an RFC4226 QR code for a tiven RTP token
|
84
|
+
def rfc4226_qrcode(token)
|
85
|
+
data = "otpauth://totp/#{request.host}?secret=#{token}"
|
86
|
+
data = Rack::Utils.escape(data)
|
87
|
+
url = "https://chart.googleapis.com/chart?chs=200x200&chld=M|0&cht=qr&chl=#{data}"
|
88
|
+
image_tag(url, :alt => 'Google Authenticator QRCode', :width => 200, :height => 200)
|
89
|
+
end
|
90
|
+
|
91
|
+
# Return a Google Fonts tag
|
92
|
+
def google_fonts(sets = {})
|
93
|
+
sets = sets.each_with_object([]) do |(name, weights), array|
|
94
|
+
array << "#{name}:#{weights.join(',')}"
|
95
|
+
end.join('|')
|
96
|
+
"<link href='https://fonts.googleapis.com/css?family=#{sets}' rel='stylesheet' type='text/css'>".html_safe
|
97
|
+
end
|
98
|
+
|
50
99
|
end
|
51
100
|
end
|
52
101
|
end
|
data/locales/en.yml
ADDED
metadata
CHANGED
@@ -1,32 +1,41 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: nifty-utils
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.1.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Adam Cooke
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2015-06-08 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
|
-
description: A set of useful utilties for Rails applications
|
13
|
+
description: A set of useful utilties for Rails applications.
|
14
14
|
email:
|
15
|
-
- adam@
|
15
|
+
- adam@atechmedia.com
|
16
16
|
executables: []
|
17
17
|
extensions: []
|
18
18
|
extra_rdoc_files: []
|
19
19
|
files:
|
20
20
|
- lib/nifty/utils.rb
|
21
|
-
- lib/nifty/utils/active_record.rb
|
21
|
+
- lib/nifty/utils/active_record/default_value.rb
|
22
|
+
- lib/nifty/utils/active_record/inquirer.rb
|
23
|
+
- lib/nifty/utils/active_record/random_string.rb
|
24
|
+
- lib/nifty/utils/auto_attribute_permit.rb
|
22
25
|
- lib/nifty/utils/extensions/core.rb
|
26
|
+
- lib/nifty/utils/extensions/object.rb
|
23
27
|
- lib/nifty/utils/extensions/string.rb
|
28
|
+
- lib/nifty/utils/http.rb
|
29
|
+
- lib/nifty/utils/networks.rb
|
24
30
|
- lib/nifty/utils/railtie.rb
|
25
31
|
- lib/nifty/utils/random_string.rb
|
32
|
+
- lib/nifty/utils/until_with_max_attempts.rb
|
26
33
|
- lib/nifty/utils/version.rb
|
27
34
|
- lib/nifty/utils/view_helpers.rb
|
28
|
-
|
29
|
-
|
35
|
+
- locales/en.yml
|
36
|
+
homepage: https://github.com/atech/nifty-utils
|
37
|
+
licenses:
|
38
|
+
- MIT
|
30
39
|
metadata: {}
|
31
40
|
post_install_message:
|
32
41
|
rdoc_options: []
|
@@ -44,9 +53,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
44
53
|
version: '0'
|
45
54
|
requirements: []
|
46
55
|
rubyforge_project:
|
47
|
-
rubygems_version: 2.
|
56
|
+
rubygems_version: 2.4.5
|
48
57
|
signing_key:
|
49
58
|
specification_version: 4
|
50
|
-
summary: A
|
59
|
+
summary: A collection of functions which expand upon ActiveRecord and ActionView.
|
51
60
|
test_files: []
|
52
|
-
has_rdoc:
|
@@ -1,38 +0,0 @@
|
|
1
|
-
module Nifty
|
2
|
-
module Utils
|
3
|
-
module ActiveRecord
|
4
|
-
|
5
|
-
#:nodoc:
|
6
|
-
def self.included(base)
|
7
|
-
base.extend ClassMethods
|
8
|
-
end
|
9
|
-
|
10
|
-
module ClassMethods
|
11
|
-
|
12
|
-
# Allows you to automatically create inquiry methods for string field. For example, if you have
|
13
|
-
# an Order model which has a status field containing 'approved' or 'delivered' you may wish to
|
14
|
-
# have a #approved? or #delivered? method on the model.
|
15
|
-
#
|
16
|
-
# class Order < ActiveRecord::Baser
|
17
|
-
# STATUSES = ['approved', 'delivered']
|
18
|
-
# inquirer :status, *STATUSES
|
19
|
-
# end
|
20
|
-
#
|
21
|
-
# order = Order.new(:status => 'approved')
|
22
|
-
# order.approved? #=> true
|
23
|
-
# order.delivered? #=> false
|
24
|
-
#
|
25
|
-
#
|
26
|
-
def inquirer(field, *options)
|
27
|
-
options.each do |option|
|
28
|
-
define_method "#{option}?" do
|
29
|
-
self.read_attribute(field).to_s == option.to_s
|
30
|
-
end
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
end
|
35
|
-
|
36
|
-
end
|
37
|
-
end
|
38
|
-
end
|