bblib 0.4.1 → 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -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