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/hash_path/part.rb
CHANGED
data/lib/html/bbhtml.rb
CHANGED
data/lib/html/builder.rb
CHANGED
@@ -8,14 +8,19 @@ module BBLib
|
|
8
8
|
SELF_CLOSING_TAGS.include?(tag.to_s.downcase)
|
9
9
|
end
|
10
10
|
|
11
|
+
def self.build(*args, &block)
|
12
|
+
Builder.build(*args, &block)
|
13
|
+
end
|
14
|
+
|
11
15
|
module Builder
|
12
16
|
|
13
17
|
BBLib::HTML::TAGS.each do |tag|
|
14
18
|
define_method(tag) do |content = nil, **attributes, &block|
|
15
19
|
context = attributes.delete(:context) || self.context
|
16
|
-
|
17
|
-
|
18
|
-
|
20
|
+
Tag.new(type: tag, attributes: attributes, content: content, context: context).tap do |t|
|
21
|
+
children << t
|
22
|
+
t.instance_eval(&block) if block
|
23
|
+
end
|
19
24
|
end
|
20
25
|
end
|
21
26
|
|
@@ -24,10 +29,14 @@ module BBLib
|
|
24
29
|
self
|
25
30
|
end
|
26
31
|
|
27
|
-
def self.build(type, content = nil, **attributes, &block)
|
28
|
-
raise ArgumentError, "Unknown element type '#{type}'." unless TAGS.include?(type.to_s.downcase)
|
32
|
+
def self.build(type = nil, content = nil, **attributes, &block)
|
33
|
+
raise ArgumentError, "Unknown element type '#{type}'." unless TAGS.include?(type.to_s.downcase) || type == nil
|
29
34
|
context = attributes.delete(:context)
|
30
|
-
|
35
|
+
if type
|
36
|
+
Tag.new(type: type, attributes: attributes, content: content, context: context, &block)
|
37
|
+
else
|
38
|
+
TagSet.new(attributes: attributes, context: context, &block)
|
39
|
+
end
|
31
40
|
end
|
32
41
|
end
|
33
42
|
end
|
data/lib/html/tag.rb
CHANGED
@@ -4,12 +4,16 @@ module BBLib
|
|
4
4
|
include BBLib::Effortless
|
5
5
|
include Builder
|
6
6
|
|
7
|
+
APPEND_ATTRIBUTES = [:class, :style].freeze
|
8
|
+
|
7
9
|
attr_str :type, required: true, arg_at: 0, arg_at_accept: [String, Symbol]
|
8
|
-
attr_str :content, arg_at: 1, arg_at_accept: [String, Symbol]
|
10
|
+
attr_str :content, default: nil, allow_nil: true, arg_at: 1, arg_at_accept: [String, Symbol]
|
9
11
|
attr_hash :attributes, default: {}
|
10
12
|
attr_ary_of Tag, :children, default: []
|
11
13
|
attr_of Object, :context, default: nil, allow_nil: true
|
12
14
|
|
15
|
+
init_type :loose
|
16
|
+
|
13
17
|
def render(pretty: false, tabs: 0)
|
14
18
|
cont = render_content(pretty: pretty, tabs: tabs)
|
15
19
|
tabbing = pretty ? ("\n" + ("\t" * tabs)) : ''
|
@@ -21,29 +25,94 @@ module BBLib
|
|
21
25
|
end
|
22
26
|
end
|
23
27
|
|
24
|
-
|
25
|
-
|
28
|
+
alias to_html render
|
29
|
+
|
30
|
+
def add(*childs)
|
31
|
+
[childs].flatten.each { |child| children.push(child) }
|
32
|
+
nil
|
33
|
+
end
|
34
|
+
|
35
|
+
def to_s(*args)
|
36
|
+
render(*args)
|
26
37
|
end
|
27
38
|
|
28
39
|
def to_str
|
29
40
|
to_s
|
30
41
|
end
|
31
42
|
|
43
|
+
def set_attribute(attribute, value)
|
44
|
+
attributes[attribute] = value
|
45
|
+
end
|
46
|
+
|
47
|
+
def append_attribute(attribute, value)
|
48
|
+
attributes[attribute] = [attributes[attribute], value.to_s].compact.join(' ')
|
49
|
+
end
|
50
|
+
|
32
51
|
def render_attributes
|
33
52
|
return nil if attributes.empty?
|
34
53
|
attributes[:style] = attributes[:style].map { |k, v| "#{k}: #{v}" }.join('; ') if attributes[:style] && attributes[:style].is_a?(Hash)
|
35
|
-
' ' + attributes.map
|
54
|
+
' ' + attributes.map do | k, v|
|
55
|
+
v = v.join(' ') if v.is_a?(Array)
|
56
|
+
"#{k}=\"#{v.to_s.gsub('"', '"')}\""
|
57
|
+
end.join(' ')
|
36
58
|
end
|
37
59
|
|
38
60
|
def render_content(pretty: false, tabs: 0)
|
39
61
|
return nil if (content.nil? || content.empty?) && children.empty?
|
40
62
|
tabbing = pretty ? ("\n" + ("\t" * (tabs + 1))) : ''
|
41
63
|
text = if content && !content.empty?
|
42
|
-
"#{tabbing}#{content.gsub("\n", tabbing)}"
|
64
|
+
"#{tabbing}#{content.gsub("\n", pretty ? tabbing : "\n")}"
|
43
65
|
end
|
44
66
|
html = children.map { |tag| tag.render(pretty: pretty, tabs: tabs + 1) }.join
|
45
67
|
[text, html].compact.join
|
46
68
|
end
|
69
|
+
|
70
|
+
def merge(attributes)
|
71
|
+
raise ArgumentError, "Expected a Hash, got a #{attributes.class}" unless attributes.is_a?(Hash)
|
72
|
+
attributes.each do |k, v|
|
73
|
+
if APPEND_ATTRIBUTES.include?(k.to_sym)
|
74
|
+
append_attribute(k, v)
|
75
|
+
else
|
76
|
+
set_attribute(k, v)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
self
|
80
|
+
end
|
81
|
+
|
82
|
+
protected
|
83
|
+
|
84
|
+
def simple_init(*args)
|
85
|
+
BBLib.named_args(*args).each do |k, v|
|
86
|
+
next if _attrs.include?(k)
|
87
|
+
self.attributes[k] = v
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def method_missing(method, *args, &block)
|
92
|
+
if context && context.respond_to?(method)
|
93
|
+
context.send(method, *args, &block)
|
94
|
+
elsif method != :to_ary
|
95
|
+
if method.to_s.encap_by?('_')
|
96
|
+
self.set_attribute(:id, method.to_s.uncapsulate('_'))
|
97
|
+
else
|
98
|
+
klass = method.to_s.gsub(/(?<=[^\_])\_(?=[^\_])/, '-').gsub('__', '_')
|
99
|
+
self.append_attribute(:class, klass)
|
100
|
+
end
|
101
|
+
self._initialize(type, *args, &block)
|
102
|
+
self
|
103
|
+
else
|
104
|
+
super
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def respond_to_missing?(method, include_private = false)
|
109
|
+
super || context && context.respond_to?(method)
|
110
|
+
end
|
111
|
+
|
112
|
+
def simple_init_block_result(value)
|
113
|
+
return false unless value && content.nil? && !value.is_a?(Tag)
|
114
|
+
self.content = value.to_s
|
115
|
+
end
|
47
116
|
end
|
48
117
|
end
|
49
118
|
end
|
data/lib/html/tag_set.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
module BBLib
|
2
|
+
module HTML
|
3
|
+
# Similar to the default tag but isn't representative of a an HTML element.
|
4
|
+
# Instead, this is a collection of nested HTML Elements, so only children of
|
5
|
+
# TagSets are rendered to html.
|
6
|
+
class TagSet < Tag
|
7
|
+
attr_str :type, required: false, default: nil, allow_nil: true
|
8
|
+
|
9
|
+
def render(pretty: false, tabs: 0)
|
10
|
+
render_content(pretty: pretty, tabs: tabs)
|
11
|
+
end
|
12
|
+
|
13
|
+
def render_content(pretty: false, tabs: 0)
|
14
|
+
return '' if children.empty?
|
15
|
+
children.map { |tag| tag.render(pretty: pretty, tabs: tabs + 1) }.join
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
data/lib/logging/bblogging.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
require :logger.to_s unless BBLib::in_opal?
|
1
2
|
|
2
3
|
module BBLib
|
3
4
|
|
@@ -12,7 +13,7 @@ module BBLib
|
|
12
13
|
if msg.is_a?(Exception)
|
13
14
|
msg = msg.inspect + "\n\t" + msg.backtrace.join("\n\t")
|
14
15
|
end
|
15
|
-
"[#{datetime}] #{severity} - #{msg}\n"
|
16
|
+
"[#{datetime}] #{severity} - #{msg.to_s.chomp}\n"
|
16
17
|
end
|
17
18
|
log.datetime_format = '%Y-%m-%d %H:%M:%S'
|
18
19
|
log
|
data/lib/mixins/attrs.rb
CHANGED
@@ -68,9 +68,15 @@ module BBLib
|
|
68
68
|
ivar = "@#{method}".to_sym
|
69
69
|
mthd_type = opts[:singleton] ? :define_singleton_method : :define_method
|
70
70
|
|
71
|
-
self.send(mthd_type, "#{method}=") do
|
72
|
-
|
73
|
-
|
71
|
+
self.send(mthd_type, "#{method}=") do |args|
|
72
|
+
if opts[:pre_proc]
|
73
|
+
if opts[:pre_proc].is_a?(Proc)
|
74
|
+
args = opts[:pre_proc].call(args)
|
75
|
+
else
|
76
|
+
args = send(opts[:pre_proc], args)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
instance_variable_set(ivar, yield(args))
|
74
80
|
end
|
75
81
|
|
76
82
|
self.send(mthd_type, method) do
|
@@ -80,7 +86,7 @@ module BBLib
|
|
80
86
|
var
|
81
87
|
elsif opts.include?(:default) || opts.include?(:default_proc)
|
82
88
|
default_value =
|
83
|
-
if opts[:default].respond_to?(:dup) && BBLib.
|
89
|
+
if opts[:default].respond_to?(:dup) && BBLib.is_any?(opts[:default], Array, Hash)
|
84
90
|
opts[:default].dup rescue opts[:default]
|
85
91
|
elsif opts[:default_proc].is_a?(Proc)
|
86
92
|
prc = opts[:default_proc]
|
@@ -115,12 +121,12 @@ module BBLib
|
|
115
121
|
allowed = [klasses].flatten
|
116
122
|
methods.each do |method|
|
117
123
|
attr_custom(method, opts.merge(_attr_type: :of, classes: klasses)) do |arg|
|
118
|
-
if BBLib.
|
124
|
+
if BBLib.is_any?(arg, *allowed) || (arg.nil? && opts[:allow_nil])
|
119
125
|
arg
|
120
126
|
elsif arg && (!opts.include?(:pack) || opts[:pack]) && arg = _attr_pack(arg, klasses, opts)
|
121
127
|
arg
|
122
128
|
else
|
123
|
-
raise
|
129
|
+
raise TypeError, "#{method} must be set to a class of #{allowed.join_terms(:or)}, not #{arg.class}" unless opts[:suppress]
|
124
130
|
end
|
125
131
|
end
|
126
132
|
end
|
@@ -178,12 +184,17 @@ module BBLib
|
|
178
184
|
|
179
185
|
def attr_integer_between(min, max, *methods, **opts)
|
180
186
|
methods.each do |method|
|
181
|
-
attr_custom(method, opts) { |arg| arg.nil? && opts[:allow_nil] ? arg : BBLib.keep_between(arg, min, max) }
|
187
|
+
attr_custom(method, opts.merge(min: min, max: max)) { |arg| arg.nil? && opts[:allow_nil] ? arg : BBLib.keep_between(arg, min, max).to_i }
|
182
188
|
end
|
183
189
|
end
|
184
190
|
|
185
191
|
alias attr_int_between attr_integer_between
|
186
|
-
|
192
|
+
|
193
|
+
def attr_float_between(min, max, *methods, **opts)
|
194
|
+
methods.each do |method|
|
195
|
+
attr_custom(method, opts.merge(min: min, max: max)) { |arg| arg.nil? && opts[:allow_nil] ? arg : BBLib.keep_between(arg, min, max).to_f }
|
196
|
+
end
|
197
|
+
end
|
187
198
|
|
188
199
|
def attr_integer_loop(min, max, *methods, **opts)
|
189
200
|
methods.each do |method|
|
@@ -208,6 +219,7 @@ module BBLib
|
|
208
219
|
end
|
209
220
|
|
210
221
|
def attr_elements_of(list, *methods, **opts)
|
222
|
+
opts[:default] = [] unless opts.include?(:default) || opts.include?(:default_proc)
|
211
223
|
methods.each do |method|
|
212
224
|
attr_custom(method, opts.merge(list: list)) do |args|
|
213
225
|
ls = list.is_a?(Proc) ? list.call : list
|
@@ -225,6 +237,7 @@ module BBLib
|
|
225
237
|
end
|
226
238
|
|
227
239
|
def attr_array(*methods, **opts)
|
240
|
+
opts[:default] = [] unless opts.include?(:default) || opts.include?(:default_proc)
|
228
241
|
methods.each do |method|
|
229
242
|
attr_custom(method, opts) do |arg|
|
230
243
|
args = arg.is_a?(Array) ? arg : [arg]
|
@@ -239,6 +252,7 @@ module BBLib
|
|
239
252
|
alias attr_ary attr_array
|
240
253
|
|
241
254
|
def attr_array_of(klasses, *methods, **opts)
|
255
|
+
opts[:default] = [] unless opts.include?(:default) || opts.include?(:default_proc)
|
242
256
|
klasses = [klasses].flatten
|
243
257
|
methods.each do |method|
|
244
258
|
attr_custom(method, opts.merge(classes: klasses)) do |args|
|
@@ -252,17 +266,17 @@ module BBLib
|
|
252
266
|
else
|
253
267
|
args = [args] unless args.is_a?(Array)
|
254
268
|
args.each do |arg|
|
255
|
-
match = BBLib.
|
269
|
+
match = BBLib.is_any?(arg, *klasses)
|
256
270
|
if match
|
257
|
-
array.push(arg)
|
271
|
+
array.push(arg)
|
258
272
|
elsif arg && (!opts.include?(:pack) || opts[:pack]) && arg = _attr_pack(arg, klasses, opts)
|
259
273
|
array.push(arg)
|
260
274
|
else
|
261
|
-
raise
|
275
|
+
raise TypeError, "Invalid class passed to #{method} on #{self}: #{arg.class}. Must be a #{klasses.join_terms(:or)}." unless opts[:raise] == false
|
262
276
|
end
|
263
277
|
end
|
264
278
|
end
|
265
|
-
array
|
279
|
+
opts[:uniq] ? array.uniq : array
|
266
280
|
end
|
267
281
|
attr_array_adder(method, opts[:adder_name], singleton: opts[:singleton]) if opts[:add_rem] || opts[:adder]
|
268
282
|
attr_array_remover(method, opts[:remover_name], singleton: opts[:singleton]) if opts[:add_rem] || opts[:remover]
|
@@ -276,7 +290,7 @@ module BBLib
|
|
276
290
|
mthd_type = singleton ? :define_singleton_method : :define_method
|
277
291
|
send(mthd_type, name) do |*args|
|
278
292
|
array = send(method)
|
279
|
-
args.each do |arg|
|
293
|
+
[args].flatten(1).each do |arg|
|
280
294
|
arg = yield(arg) if block_given?
|
281
295
|
array.push(arg)
|
282
296
|
end
|
@@ -288,7 +302,7 @@ module BBLib
|
|
288
302
|
name = "remove_#{method}" unless name
|
289
303
|
define_method(name) do |*args|
|
290
304
|
array = instance_variable_get("@#{method}")
|
291
|
-
args.map do |arg|
|
305
|
+
[args].flatten(1).map do |arg|
|
292
306
|
next unless array && !array.empty?
|
293
307
|
array.delete(arg)
|
294
308
|
end
|
@@ -328,8 +342,8 @@ module BBLib
|
|
328
342
|
attr_custom(method, **opts) do |arg|
|
329
343
|
if opts[:formats]
|
330
344
|
arg = arg.to_s
|
331
|
-
opts[:
|
332
|
-
arg = Time.
|
345
|
+
[opts[:formats]].flatten.each do |format|
|
346
|
+
arg = Time.strptime(arg, format) rescue arg
|
333
347
|
end
|
334
348
|
end
|
335
349
|
if arg.is_a?(Time) || arg.nil? && opts[:allow_nil]
|
@@ -339,7 +353,7 @@ module BBLib
|
|
339
353
|
else
|
340
354
|
begin
|
341
355
|
Time.parse(arg.to_s)
|
342
|
-
rescue =>
|
356
|
+
rescue => _e
|
343
357
|
nil
|
344
358
|
end
|
345
359
|
end
|
@@ -352,8 +366,8 @@ module BBLib
|
|
352
366
|
attr_custom(method, **opts) do |arg|
|
353
367
|
if opts[:formats]
|
354
368
|
arg = arg.to_s
|
355
|
-
opts[:
|
356
|
-
arg = Date.
|
369
|
+
[opts[:formats]].flatten.each do |format|
|
370
|
+
arg = Date.strptime(arg, format) rescue arg
|
357
371
|
end
|
358
372
|
end
|
359
373
|
if arg.is_a?(Date) || arg.nil? && opts[:allow_nil]
|
@@ -363,7 +377,7 @@ module BBLib
|
|
363
377
|
else
|
364
378
|
begin
|
365
379
|
Date.parse(arg.to_s)
|
366
|
-
rescue =>
|
380
|
+
rescue => _e
|
367
381
|
nil
|
368
382
|
end
|
369
383
|
end
|
@@ -372,12 +386,13 @@ module BBLib
|
|
372
386
|
end
|
373
387
|
|
374
388
|
def attr_hash(*methods, **opts)
|
389
|
+
opts[:default] = {} unless opts.include?(:default) || opts.include?(:default_proc)
|
375
390
|
methods.each do |method|
|
376
391
|
attr_custom(method, **opts) do |arg|
|
377
392
|
raise ArgumentError, "#{method} must be set to a hash, not a #{arg.class} (for #{self})." unless arg.is_a?(Hash) || arg.nil? && opts[:allow_nil]
|
378
393
|
if opts[:keys] && arg
|
379
394
|
arg.keys.each do |key|
|
380
|
-
if BBLib.
|
395
|
+
if BBLib.is_any?(key, *opts[:keys])
|
381
396
|
next
|
382
397
|
elsif (opts.include?(:pack_key) && opts[:pack_key]) && new_key = _attr_pack(key, klasses, opts)
|
383
398
|
arg[new_key] = arg.delete(key)
|
@@ -388,12 +403,12 @@ module BBLib
|
|
388
403
|
end
|
389
404
|
if opts[:values] && arg
|
390
405
|
arg.each do |key, value|
|
391
|
-
if BBLib.
|
406
|
+
if BBLib.is_any?(value, *opts[:values])
|
392
407
|
next
|
393
408
|
elsif (!opts.include?(:pack_value) || opts[:pack_value]) && value = _attr_pack(value, klasses, opts)
|
394
409
|
arg[key] = arg.delete(value)
|
395
410
|
else
|
396
|
-
raise
|
411
|
+
raise TypeError, "Invalid value type for #{method}: #{value.class}. Must be #{opts[:values].join_terms(:or)}."
|
397
412
|
end
|
398
413
|
end
|
399
414
|
end
|
@@ -405,8 +420,8 @@ module BBLib
|
|
405
420
|
|
406
421
|
def _attr_pack(arg, klasses, opts = {})
|
407
422
|
klasses = [klasses].flatten
|
408
|
-
unless BBLib.
|
409
|
-
return klasses.first.new(*[arg].flatten(1))
|
423
|
+
unless BBLib.is_any?(arg, *klasses)
|
424
|
+
return klasses.first.new(*[arg].flatten(1)) if klasses.first.respond_to?(:new)
|
410
425
|
end
|
411
426
|
nil
|
412
427
|
end
|
data/lib/mixins/bbmixins.rb
CHANGED
data/lib/mixins/family_tree.rb
CHANGED
@@ -6,6 +6,7 @@ module BBLib
|
|
6
6
|
module FamilyTree
|
7
7
|
# Return all classes that inherit from this class
|
8
8
|
def descendants(include_singletons = false)
|
9
|
+
return _inherited_by.map { |c| [c, c.descendants] }.flatten.uniq if BBLib.in_opal?
|
9
10
|
ObjectSpace.each_object(Class).select do |c|
|
10
11
|
(include_singletons || !c.singleton_class?) && c < self
|
11
12
|
end
|
@@ -15,6 +16,7 @@ module BBLib
|
|
15
16
|
|
16
17
|
# Return all classes that directly inherit from this class
|
17
18
|
def direct_descendants(include_singletons = false)
|
19
|
+
return _inherited_by if BBLib.in_opal?
|
18
20
|
ObjectSpace.each_object(Class).select do |c|
|
19
21
|
(include_singletons || !c.singleton_class?) && c.ancestors[1] == self
|
20
22
|
end
|
@@ -37,5 +39,15 @@ module BBLib
|
|
37
39
|
|
38
40
|
alias direct_subclasses direct_descendants
|
39
41
|
|
42
|
+
# If we are in Opal we need to track descendants a bit differently
|
43
|
+
if BBLib.in_opal?
|
44
|
+
def _inherited_by
|
45
|
+
@_inherited_by ||= []
|
46
|
+
end
|
47
|
+
|
48
|
+
def inherited(klass)
|
49
|
+
_inherited_by.push(klass)
|
50
|
+
end
|
51
|
+
end
|
40
52
|
end
|
41
53
|
end
|