bblib 0.4.1 → 1.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +12 -11
- data/.rspec +2 -2
- data/.travis.yml +4 -4
- data/CODE_OF_CONDUCT.md +13 -13
- data/Gemfile +4 -4
- data/LICENSE.txt +21 -21
- data/Rakefile +6 -6
- data/bblib.gemspec +34 -34
- data/bin/console +14 -14
- data/bin/setup +7 -7
- data/lib/array/bbarray.rb +2 -2
- data/lib/bblib.rb +1 -0
- data/lib/bblib/version.rb +1 -1
- data/lib/class/effortless.rb +2 -2
- data/lib/file/bbfile.rb +10 -8
- data/lib/hash/bbhash.rb +23 -15
- data/lib/hash/hash_struct.rb +1 -1
- data/lib/hash/tree_hash.rb +1 -1
- data/lib/hash_path/hash_path.rb +3 -3
- data/lib/hash_path/part.rb +2 -2
- data/lib/html/bbhtml.rb +1 -0
- data/lib/html/builder.rb +15 -6
- data/lib/html/tag.rb +74 -5
- data/lib/html/tag_set.rb +20 -0
- data/lib/logging/bblogging.rb +2 -1
- data/lib/mixins/attrs.rb +40 -25
- data/lib/mixins/bbmixins.rb +2 -0
- data/lib/mixins/family_tree.rb +12 -0
- data/lib/mixins/hooks.rb +8 -1
- data/lib/mixins/logger.rb +10 -10
- data/lib/mixins/prototype.rb +26 -0
- data/lib/mixins/simple_init.rb +47 -17
- data/lib/mixins/type_init.rb +21 -0
- data/lib/number/bbnumber.rb +90 -0
- data/lib/object/bbobject.rb +1 -5
- data/lib/opal/bbopal.rb +5 -0
- data/lib/os/bbos.rb +0 -63
- data/lib/string/bbstring.rb +22 -1
- data/lib/string/cases.rb +4 -4
- data/lib/time/bbtime.rb +27 -0
- data/lib/time/task_timer.rb +3 -1
- metadata +4 -2
- data/lib/os/bbsys.rb +0 -255
data/lib/mixins/hooks.rb
CHANGED
@@ -83,17 +83,21 @@ module BBLib
|
|
83
83
|
# modify_args - Replaces the original args with the returned value of the
|
84
84
|
# send_method - Sends the method name as an argument to the hooked method.
|
85
85
|
# before hook method.
|
86
|
+
# try_first - Sends the args to the desired hook first and if the result
|
87
|
+
# is non-nil, the result is sent instead of calling the hooked
|
88
|
+
# method.
|
86
89
|
def _hook_before_method(method, hook, opts = {})
|
87
90
|
return false if method == hook
|
88
91
|
_add_hooked_method(:before, hook, method)
|
89
92
|
original = instance_method(method)
|
90
93
|
@_defining_hook = true
|
91
94
|
define_method(method) do |*args, &block|
|
92
|
-
if opts[:send_args] || opts[:send_arg] || opts[:modify_args] || opts[:send_method]
|
95
|
+
if opts[:send_args] || opts[:send_arg] || opts[:modify_args] || opts[:send_method] || opts[:try_first]
|
93
96
|
margs = args
|
94
97
|
margs = [method] + args if opts[:send_method]
|
95
98
|
margs = args + [opts[:add_args]].flatten(1) if opts[:add_args]
|
96
99
|
result = method(hook).call(*margs)
|
100
|
+
return result if result && opts[:try_first]
|
97
101
|
args = result if opts[:modify_args]
|
98
102
|
else
|
99
103
|
method(hook).call
|
@@ -112,6 +116,7 @@ module BBLib
|
|
112
116
|
# modify_value - Opts must also include one of the two above. Passes the returned
|
113
117
|
# => value of the method to the hook and returns the hooks value
|
114
118
|
# => rather than the original methods value.
|
119
|
+
# send_all - Sends a hash containing the args, method and value (return).
|
115
120
|
def _hook_after_method(method, hook, opts = {})
|
116
121
|
return false if method == hook
|
117
122
|
_add_hooked_method(:after, hook, method)
|
@@ -127,6 +132,8 @@ module BBLib
|
|
127
132
|
elsif opts[:send_return_ary] || opts[:send_value_ary]
|
128
133
|
result = method(hook).call(*rtr)
|
129
134
|
rtr = result if opts[:modify_value] || opts[:modify_return]
|
135
|
+
elsif opts[:send_all]
|
136
|
+
result = method(hook).call(args: args, value: rtr, method: method)
|
130
137
|
else
|
131
138
|
method(hook).call
|
132
139
|
end
|
data/lib/mixins/logger.rb
CHANGED
@@ -5,11 +5,11 @@ module BBLib
|
|
5
5
|
self.class.logger
|
6
6
|
end
|
7
7
|
|
8
|
-
[:debug, :info, :warn, :error, :fatal, :unknown].each do |sev|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
end
|
8
|
+
# [:debug, :info, :warn, :error, :fatal, :unknown].each do |sev|
|
9
|
+
# define_method(sev) do |msg = nil, &block|
|
10
|
+
# logger.send(sev) { "[#{self.class}] #{msg ? msg : block.call}" }
|
11
|
+
# end
|
12
|
+
# end
|
13
13
|
|
14
14
|
def self.included(base)
|
15
15
|
base.extend ClassMethods
|
@@ -20,11 +20,11 @@ module BBLib
|
|
20
20
|
BBLib.logger
|
21
21
|
end
|
22
22
|
|
23
|
-
[:debug, :info, :warn, :error, :fatal, :unknown].each do |sev|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
end
|
23
|
+
# [:debug, :info, :warn, :error, :fatal, :unknown].each do |sev|
|
24
|
+
# define_method(sev) do |msg = nil, &block|
|
25
|
+
# logger.send(sev) { "[#{self}] #{msg ? msg : block.call}" }
|
26
|
+
# end
|
27
|
+
# end
|
28
28
|
end
|
29
29
|
|
30
30
|
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
|
2
|
+
module BBLib
|
3
|
+
module Prototype
|
4
|
+
def self.included(base)
|
5
|
+
base.extend(ClassMethods)
|
6
|
+
end
|
7
|
+
|
8
|
+
module ClassMethods
|
9
|
+
def prototype(opts = prototype_defaults)
|
10
|
+
@prototype ||= self.new(*prototype_defaults)
|
11
|
+
end
|
12
|
+
|
13
|
+
def prototype_defaults
|
14
|
+
[]
|
15
|
+
end
|
16
|
+
|
17
|
+
def method_missing(method, *args, &block)
|
18
|
+
prototype.respond_to?(method) ? prototype.send(method, *args, &block) : super
|
19
|
+
end
|
20
|
+
|
21
|
+
def respond_to_missing?(method, include_private = false)
|
22
|
+
prototype.respond_to?(method) || super
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
data/lib/mixins/simple_init.rb
CHANGED
@@ -14,32 +14,56 @@ module BBLib
|
|
14
14
|
define_method(:initialize) do |*args, &block|
|
15
15
|
send(:simple_setup) if respond_to?(:simple_setup, true)
|
16
16
|
send(:simple_preinit, *args, &block) if respond_to?(:simple_preinit, true)
|
17
|
-
_initialize(*args)
|
17
|
+
_initialize(*args, &block)
|
18
18
|
send(:simple_init, *args, &block) if respond_to?(:simple_init, true)
|
19
|
-
|
19
|
+
if block && !_attrs.any? { |k, v| v[:options][:arg_at] == :block }
|
20
|
+
result = instance_eval(&block)
|
21
|
+
simple_init_block_result(result) if respond_to?(:simple_init_block_result, true)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
if BBLib.in_opal?
|
27
|
+
base.singleton_class.class_eval do
|
28
|
+
alias __new new
|
29
|
+
|
30
|
+
def new(*args, &block)
|
31
|
+
named = BBLib.named_args(*args)
|
32
|
+
if init_foundation && named[init_foundation_method] && ((named[init_foundation_method] != self.send(init_foundation_method)) rescue false)
|
33
|
+
klass = [self, descendants].flatten.find do |k|
|
34
|
+
if init_foundation_compare
|
35
|
+
init_foundation_compare.call(k.send(init_foundation_method), named[init_foundation_method])
|
36
|
+
else
|
37
|
+
k.send(init_foundation_method).to_s == named[init_foundation_method].to_s
|
38
|
+
end
|
39
|
+
end
|
40
|
+
raise ArgumentError, "Unknown #{init_foundation_method} \"#{named[init_foundation_method]}\" for #{self}" unless klass
|
41
|
+
klass == self ? __new(*args, &block) : klass.new(*args, &block)
|
42
|
+
else
|
43
|
+
__new(*args, &block)
|
44
|
+
end
|
45
|
+
end
|
20
46
|
end
|
21
47
|
end
|
22
48
|
end
|
23
49
|
|
24
50
|
module ClassMethods
|
25
51
|
|
26
|
-
# TODO: Currently init foundation breaks when running in opal.
|
27
52
|
unless BBLib.in_opal?
|
28
53
|
# Overriden new method that allows parent classes to dynamically generate
|
29
|
-
# instantiations of descendants by using the named
|
30
|
-
# :_class needs to be the fully qualified name of the descendant.
|
54
|
+
# instantiations of descendants by using the named init_foundation_method argument.
|
31
55
|
def new(*args, &block)
|
32
56
|
named = BBLib.named_args(*args)
|
33
57
|
if init_foundation && named[init_foundation_method] && ((named[init_foundation_method] != self.send(init_foundation_method)) rescue false)
|
34
|
-
klass = descendants.find do |k|
|
58
|
+
klass = [self, descendants].flatten.find do |k|
|
35
59
|
if init_foundation_compare
|
36
60
|
init_foundation_compare.call(k.send(init_foundation_method), named[init_foundation_method])
|
37
61
|
else
|
38
62
|
k.send(init_foundation_method).to_s == named[init_foundation_method].to_s
|
39
63
|
end
|
40
64
|
end
|
41
|
-
raise ArgumentError, "Unknown
|
42
|
-
klass.new(*args, &block)
|
65
|
+
raise ArgumentError, "Unknown #{init_foundation_method} \"#{named[init_foundation_method]}\"" unless klass
|
66
|
+
klass == self ? super : klass.new(*args, &block)
|
43
67
|
else
|
44
68
|
super
|
45
69
|
end
|
@@ -65,14 +89,14 @@ module BBLib
|
|
65
89
|
end
|
66
90
|
|
67
91
|
def init_foundation_compare(&block)
|
68
|
-
@init_foundation_compare = block if
|
92
|
+
@init_foundation_compare = block if block
|
69
93
|
@init_foundation_compare
|
70
94
|
end
|
71
95
|
|
72
96
|
def setup_init_foundation(method, &block)
|
73
97
|
self.init_foundation = true
|
74
98
|
self.init_foundation_method(method)
|
75
|
-
self.init_foundation_compare(&block) if
|
99
|
+
self.init_foundation_compare(&block) if block
|
76
100
|
end
|
77
101
|
|
78
102
|
def ancestor_init_foundation_method
|
@@ -127,17 +151,23 @@ module BBLib
|
|
127
151
|
|
128
152
|
protected
|
129
153
|
|
130
|
-
def _initialize(*args)
|
154
|
+
def _initialize(*args, &block)
|
131
155
|
named = BBLib.named_args(*args)
|
132
156
|
if self.class.respond_to?(:_attrs)
|
133
157
|
set_v_arg = self.class._attrs.map do |method, details|
|
134
|
-
next unless details[:options][:arg_at] && details[:options][:arg_at].is_a?(Integer)
|
158
|
+
next unless details[:options][:arg_at] && (details[:options][:arg_at].is_a?(Integer) || details[:options][:arg_at] == :block)
|
159
|
+
if details[:options][:arg_at] == :block
|
160
|
+
send("#{method}=", block) if block
|
161
|
+
method
|
162
|
+
else
|
135
163
|
index = details[:options][:arg_at]
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
164
|
+
if args.size > index
|
165
|
+
accept = details[:options][:arg_at_accept]
|
166
|
+
next if args[index].is_a?(Hash) && (accept.nil? || ![accept].flatten.include?(Hash))
|
167
|
+
if accept.nil? || [accept].flatten.any? { |a| a >= args[index].class }
|
168
|
+
send("#{method}=", args[index])
|
169
|
+
method
|
170
|
+
end
|
141
171
|
end
|
142
172
|
end
|
143
173
|
end.compact
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module BBLib
|
2
|
+
# Requires Simple init to be loaded first. This sets up a very basic
|
3
|
+
# init foundation by adding a method called type and setting the init
|
4
|
+
# foundation method to it.
|
5
|
+
module TypeInit
|
6
|
+
|
7
|
+
def self.included(base)
|
8
|
+
base.extend(ClassMethods)
|
9
|
+
base.send(:bridge_method, :type)
|
10
|
+
base.send(:serialize_method, :type, always: true)
|
11
|
+
base.send(:setup_init_foundation, :type) { |a, b| a && b && a.to_s.to_sym == b.to_s.to_sym }
|
12
|
+
end
|
13
|
+
|
14
|
+
module ClassMethods
|
15
|
+
def type
|
16
|
+
to_s.split('::').last.method_case.to_sym
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
data/lib/number/bbnumber.rb
CHANGED
@@ -17,4 +17,94 @@ module BBLib
|
|
17
17
|
num = min if max && num > max
|
18
18
|
num
|
19
19
|
end
|
20
|
+
|
21
|
+
NUMBER_WORDS = {
|
22
|
+
special: {
|
23
|
+
0 => nil,
|
24
|
+
1 => 'one',
|
25
|
+
2 => 'two',
|
26
|
+
3 => 'three',
|
27
|
+
4 => 'four',
|
28
|
+
5 => 'five',
|
29
|
+
6 => 'six',
|
30
|
+
7 => 'seven',
|
31
|
+
8 => 'eight',
|
32
|
+
9 => 'nine',
|
33
|
+
10 => 'ten',
|
34
|
+
11 => 'eleven',
|
35
|
+
12 => 'twleve',
|
36
|
+
13 => 'thirteen',
|
37
|
+
14 => 'fourteen',
|
38
|
+
15 => 'fifteen',
|
39
|
+
16 => 'sixteen',
|
40
|
+
17 => 'seventeen',
|
41
|
+
18 => 'eighteen',
|
42
|
+
19 => 'nineteen'
|
43
|
+
},
|
44
|
+
double_range: {
|
45
|
+
2 => 'twenty',
|
46
|
+
3 => 'thirty',
|
47
|
+
4 => 'forty',
|
48
|
+
5 => 'fifty',
|
49
|
+
6 => 'sixty',
|
50
|
+
7 => 'seventy',
|
51
|
+
8 => 'eighty',
|
52
|
+
9 => 'ninety'
|
53
|
+
},
|
54
|
+
ranges: [
|
55
|
+
nil, 'thousand', 'million', 'billion', 'trillion', 'quadrillion',
|
56
|
+
'quintillion', 'sextillion', 'septillion'
|
57
|
+
]
|
58
|
+
}
|
59
|
+
|
60
|
+
def self.number_spelled_out(number, range = 0, include_and: true)
|
61
|
+
number = number.to_i
|
62
|
+
negative = number.negative?
|
63
|
+
number = number * -1 if negative
|
64
|
+
return 'zero' if number.zero?
|
65
|
+
str = []
|
66
|
+
three_digit = number > 999 ? number.to_s[-3..-1].to_i : number
|
67
|
+
case three_digit
|
68
|
+
when 1..19
|
69
|
+
str << NUMBER_WORDS[:special][three_digit]
|
70
|
+
when 20..99
|
71
|
+
str << NUMBER_WORDS[:double_range][three_digit.to_s[-2].to_i]
|
72
|
+
str << NUMBER_WORDS[:special][three_digit.to_s[-1].to_i]
|
73
|
+
when 100..999
|
74
|
+
str << NUMBER_WORDS[:special][three_digit.to_s[0].to_i]
|
75
|
+
str << 'hundred'
|
76
|
+
str << 'and' if include_and
|
77
|
+
if three_digit.to_s[-2].to_i == 1
|
78
|
+
str << NUMBER_WORDS[:special][three_digit.to_s[-2..-1].to_i]
|
79
|
+
else
|
80
|
+
str << NUMBER_WORDS[:double_range][three_digit.to_s[-2].to_i]
|
81
|
+
str << NUMBER_WORDS[:special][three_digit.to_s[-1].to_i]
|
82
|
+
end
|
83
|
+
end
|
84
|
+
str << NUMBER_WORDS[:ranges][range] unless str.compact.empty?
|
85
|
+
(negative ? 'negative ' : '') +
|
86
|
+
((number.to_s.size > 3 ? "#{number_spelled_out(number.to_s[0..-4].to_i, range + 1)} " : '') +
|
87
|
+
str.compact.join(' ')).gsub(/\s+/, ' ')
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
class Integer
|
92
|
+
# Convert this integer into a string with every three digits separated by a delimiter
|
93
|
+
def to_delimited_s(delim = ',')
|
94
|
+
self.to_s.reverse.gsub(/(\d{3})/, "\\1#{delim}").reverse.uncapsulate(',')
|
95
|
+
end
|
96
|
+
|
97
|
+
def spell_out
|
98
|
+
BBLib.number_spelled_out(self)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
class Float
|
103
|
+
# Convert this integer into a string with every three digits separated by a delimiter
|
104
|
+
# on the left side of the decimal
|
105
|
+
def to_delimited_s(delim = ',')
|
106
|
+
split = self.to_s.split('.')
|
107
|
+
split[0] = split.first.reverse.gsub(/(\d{3})/, "\\1#{delim}").reverse
|
108
|
+
split.join('.').uncapsulate(',')
|
109
|
+
end
|
20
110
|
end
|
data/lib/object/bbobject.rb
CHANGED
@@ -1,13 +1,9 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
# require_relative 'attr'
|
3
|
-
# require_relative 'hooks'
|
4
|
-
|
5
1
|
module BBLib
|
6
2
|
def self.are_all?(klass, *vars)
|
7
3
|
vars.all? { |var| var.is_a?(klass) }
|
8
4
|
end
|
9
5
|
|
10
|
-
def self.
|
6
|
+
def self.is_any?(obj, *klasses)
|
11
7
|
klasses.any? { |klass| obj.is_a?(klass) }
|
12
8
|
end
|
13
9
|
|
data/lib/opal/bbopal.rb
CHANGED
@@ -2,11 +2,16 @@ module BBLib
|
|
2
2
|
def self.in_opal?
|
3
3
|
RUBY_ENGINE == 'opal'
|
4
4
|
end
|
5
|
+
|
6
|
+
# Used when a method is called while in the wrong engine (such as Opal)
|
7
|
+
class WrongEngineError < StandardError; end
|
5
8
|
end
|
6
9
|
|
7
10
|
if BBLib.in_opal?
|
8
11
|
class Element
|
9
12
|
alias_native :replace_with, :replaceWith
|
10
13
|
alias_native :prepend
|
14
|
+
alias_native :insert_after, :insertAfter
|
15
|
+
alias_native :insert_before, :insertBefore
|
11
16
|
end
|
12
17
|
end
|
data/lib/os/bbos.rb
CHANGED
@@ -1,5 +1,3 @@
|
|
1
|
-
require_relative 'bbsys'
|
2
|
-
|
3
1
|
module BBLib
|
4
2
|
module OS
|
5
3
|
def self.os
|
@@ -26,67 +24,6 @@ module BBLib
|
|
26
24
|
!(/#{builds.join('|')}/i =~ RUBY_PLATFORM).nil?
|
27
25
|
end
|
28
26
|
|
29
|
-
def self.os_info
|
30
|
-
if windows?
|
31
|
-
data = `wmic os get manufacturer,name,organization,osarchitecture,version /format:list`
|
32
|
-
data = data.split("\n").reject { |r| r.strip == '' }.map do |m|
|
33
|
-
spl = m.split('=')
|
34
|
-
[spl.first.to_clean_sym.downcase, spl[1..-1].join('=')]
|
35
|
-
end.to_h
|
36
|
-
data[:name] = data[:name].split('|').first
|
37
|
-
data[:osarchitecture] = data[:osarchitecture].extract_integers.first
|
38
|
-
data.hpath_move('osarchitecture' => 'bits')
|
39
|
-
data[:host] = `hostname`.strip
|
40
|
-
data[:os] = os
|
41
|
-
data
|
42
|
-
else
|
43
|
-
release = {}
|
44
|
-
begin
|
45
|
-
# First attempt to get release info uses lsb_release
|
46
|
-
release = `lsb_release -a`.split("\n").map do |l|
|
47
|
-
spl = l.split(':')
|
48
|
-
[
|
49
|
-
spl.first.downcase.to_clean_sym,
|
50
|
-
spl[1..-1].join(':').strip
|
51
|
-
]
|
52
|
-
end.to_h
|
53
|
-
release.hpath_move('description' => 'name', 'release' => 'name', 'distributor_id' => 'manufacturer')
|
54
|
-
rescue
|
55
|
-
# Try finding the release file and parsing it instead of lsb_release
|
56
|
-
begin
|
57
|
-
release = `cat /etc/*release`
|
58
|
-
.split("\n")
|
59
|
-
.reject { |l| !(l.include?(':') || l.include?('=')) }
|
60
|
-
.map { |l| l.msplit('=', ':') }
|
61
|
-
.map { |a| [a.first.downcase.to_clean_sym, a[1..-1].join(':').uncapsulate] }
|
62
|
-
.to_h
|
63
|
-
rescue StandardError => e
|
64
|
-
# Both attempts failed
|
65
|
-
end
|
66
|
-
end
|
67
|
-
{
|
68
|
-
release: `uname -r`.strip,
|
69
|
-
bits: `uname -r` =~ /x86_64/i ? 64 : 32,
|
70
|
-
host: `uname -n`.strip,
|
71
|
-
os: os
|
72
|
-
}.merge(release)
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
# The following is Windows specific code
|
77
|
-
if windows?
|
78
|
-
|
79
|
-
def self.parse_wmic(cmd)
|
80
|
-
`#{cmd} /format:list`
|
81
|
-
.split("\n\n\n").reject(&:empty?)
|
82
|
-
.map do |l|
|
83
|
-
l.split("\n\n")
|
84
|
-
.map { |l| spl = l.split('='); [spl.first.strip.downcase.to_clean_sym, spl[1..-1].join('=').strip] }.to_h
|
85
|
-
end.reject(&:empty?)
|
86
|
-
end
|
87
|
-
|
88
|
-
end
|
89
|
-
|
90
27
|
# Mostly platform agnost way to find the full path of an executable in the current env path.
|
91
28
|
def self.which(cmd)
|
92
29
|
ENV['PATH'].split(File::PATH_SEPARATOR).each do |path|
|
data/lib/string/bbstring.rb
CHANGED
@@ -94,6 +94,27 @@ module BBLib
|
|
94
94
|
str_b
|
95
95
|
end
|
96
96
|
end
|
97
|
+
|
98
|
+
# Pattern render takes (by default) a mustache style template and then uses
|
99
|
+
# a context (either a Hash or Object) to then interpolate in placeholders.
|
100
|
+
# The default pattern looks for {{method_name}} within the string but can be
|
101
|
+
# customized to a different pattern by setting the pattern named argument.
|
102
|
+
def self.pattern_render(text, context = {}, pattern: /\{{2}.*?\}{2}/, field_pattern: /(?<=^\{{2}).*(?=\}{2})/)
|
103
|
+
raise ArgumentError, "Expected text argument to be a String, got a #{text.class}" unless text.is_a?(String)
|
104
|
+
txt = text.dup
|
105
|
+
txt.scan(pattern).each do |match|
|
106
|
+
field = match.scan(field_pattern).first
|
107
|
+
next unless field
|
108
|
+
value = case context
|
109
|
+
when Hash
|
110
|
+
context[field.to_sym] || context[field]
|
111
|
+
else
|
112
|
+
context.send(field) if context.respond_to?(field)
|
113
|
+
end.to_s
|
114
|
+
txt.sub!(match, value)
|
115
|
+
end
|
116
|
+
txt
|
117
|
+
end
|
97
118
|
end
|
98
119
|
|
99
120
|
class String
|
@@ -130,7 +151,7 @@ class String
|
|
130
151
|
else
|
131
152
|
encapsulator
|
132
153
|
end
|
133
|
-
patterns = delimiters.map { |d| /#{d}(?=(?:[^#{pattern}]|[#{pattern}][^#{pattern}]*[#{pattern}])*$)/}
|
154
|
+
patterns = delimiters.map { |d| /#{Regexp.escape(d)}(?=(?:[^#{pattern}]|[#{pattern}][^#{pattern}]*[#{pattern}])*$)/}
|
134
155
|
msplit(*patterns)
|
135
156
|
end
|
136
157
|
|