bblib 0.4.1 → 1.0.2

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.
@@ -75,8 +75,8 @@ class HashPath
75
75
  elsif str =~ /\[\-?\d+\.{2,3}\-?\d+\]/
76
76
  Range.new(*str.scan(/\-?\d+/).map(&:to_i))
77
77
  else
78
- str
79
- end.gsub('\\.', '.')
78
+ str.gsub('\\.', '.')
79
+ end
80
80
  end
81
81
 
82
82
  end
data/lib/html/bbhtml.rb CHANGED
@@ -1,2 +1,3 @@
1
1
  require_relative 'builder'
2
2
  require_relative 'tag'
3
+ require_relative 'tag_set'
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
- t = Tag.new(type: tag, attributes: attributes, content: content, context: context)
17
- children << t
18
- t.instance_eval(&block) if block
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
- Tag.new(type: type, content: content, attributes: attributes, context: context, &block)
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
- def to_s
25
- render
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 { | k, v| "#{k}=\"#{v.to_s.gsub('"', '&#34;')}\"" }.join(' ')
54
+ ' ' + attributes.map do | k, v|
55
+ v = v.join(' ') if v.is_a?(Array)
56
+ "#{k}=\"#{v.to_s.gsub('"', '&#34;')}\""
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
@@ -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
@@ -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 |*args|
72
- args = opts[:pre_proc].call(*args) if opts[:pre_proc]
73
- instance_variable_set(ivar, (args.is_a?(Array) ? yield(*args) : yield(args)))
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.is_a?(opts[:default], Array, Hash)
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.is_a?(arg, *allowed) || (arg.nil? && opts[:allow_nil])
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 ArgumentError, "#{method} must be set to a class of #{allowed.join_terms(:or)}, NOT #{arg.class}" unless opts[:suppress]
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
- alias attr_float_between attr_integer_between
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.is_a?(arg, *klasses)
269
+ match = BBLib.is_any?(arg, *klasses)
256
270
  if match
257
- array.push(arg) if match
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 ArgumentError, "Invalid class passed to #{method}: #{arg.class}. Must be a #{klasses.join_terms(:or)}." unless opts[:raise] == false
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[:format].each do |format|
332
- arg = Time.strftime(arg, format) rescue arg
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 => e
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[:format].each do |format|
356
- arg = Date.strftime(arg, format) rescue arg
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 => e
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.is_a?(key, *opts[:keys])
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.is_a?(value, *opts[:values])
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 ArgumentError, "Invalid value type for #{method}: #{value.class}. Must be #{opts[:values].join_terms(:or)}."
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.is_a?(arg, *klasses)
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
@@ -5,3 +5,5 @@ require_relative 'hooks'
5
5
  require_relative 'serializer'
6
6
  require_relative 'logger'
7
7
  require_relative 'bridge'
8
+ require_relative 'prototype'
9
+ require_relative 'type_init'
@@ -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