bblib 0.2.2 → 0.3.0

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.
@@ -1,20 +1,23 @@
1
1
  require 'time'
2
2
 
3
3
  class Hash
4
- def hash_path_proc action, paths, *args, **params
5
- BBLib.hash_path_proc self, action, paths, *args, **params
4
+ def path_proc action, paths, *args
5
+ BBLib.hash_path_proc self, action, paths, *args
6
6
  end
7
+
8
+ alias_method :hash_path_proc, :path_proc
7
9
  end
8
10
 
9
11
  class Array
10
- def hash_path_proc action, paths, *args, **params
11
- BBLib.hash_path_proc self, action, paths, *args, **params
12
+ def hash_path_proc action, paths, *args
13
+ BBLib.hash_path_proc self, action, paths, *args
12
14
  end
13
15
  end
14
16
 
15
17
  module BBLib
16
18
 
17
- def self.hash_path_proc hash, action, paths, *args, **params
19
+ def self.hash_path_proc hash, action, paths, *args
20
+ params = BBLib::named_args(*args)
18
21
  action = HASH_PATH_PROC_TYPES.keys.find{ |k| k == action || HASH_PATH_PROC_TYPES[k][:aliases].include?(action) }
19
22
  return nil unless action
20
23
  paths.to_a.each do |path|
@@ -26,91 +29,89 @@ module BBLib
26
29
  next
27
30
  end
28
31
  end
29
- HashPath.send(action, hash, path, value, *args, **params)
32
+ HashPath.send(action, hash, path, value, *args)
30
33
  end
31
34
  end
32
35
  return hash
33
36
  end
34
37
 
35
38
  HASH_PATH_PROC_TYPES = {
36
- evaluate: { aliases: [:eval, :equation, :equate]},
37
- append: { aliases: [:suffix]},
38
- prepend: { aliases: [:prefix]},
39
- split: { aliases: [:delimit, :delim, :separate, :msplit]},
40
- replace: { aliases: [:swap]},
41
- extract: { aliases: [:grab, :scan]},
42
- extract_first: {aliases: [:grab_first, :scan_first]},
43
- extract_last: {aliases: [:grab_last, :scan_last]},
44
- parse_date: { aliases: [:date, :parse_time, :time]},
45
- parse_date_unix: { aliases: [:unix_time, :unix_date]},
46
- parse_duration: { aliases: [:duration]},
47
- parse_file_size: { aliases: [:file_size]},
48
- to_string: {aliases: [:to_s, :stringify]},
49
- downcase: { aliases: [:lower, :lowercase, :to_lower]},
50
- upcase: { aliases: [:upper, :uppercase, :to_upper]},
51
- roman: { aliases: [:convert_roman, :roman_numeral, :parse_roman]},
52
- remove_symbols: { aliases: [:chop_symbols, :drop_symbols]},
53
- format_articles: { aliases: [:articles]},
54
- reverse: { aliases: [:invert]},
55
- delete: { aliases: [:del]},
56
- remove: { aliases: [:rem]},
57
- custom: {aliases: [:send]},
58
- # TODO
59
- # titlecase: { aliases: [:title_case]},
60
- encapsulate: {aliases: []},
61
- uncapsulate: {aliases: []},
62
- extract_integers: {aliases: [:extract_ints]},
63
- extract_floats: {aliases: []},
64
- extract_numbers: {aliases: []},
65
- max_number: {aliases: [:max, :maximum, :maximum_number]},
66
- min_number: {aliases: [:min, :minimum, :minimum_number]},
67
- avg_number: {aliases: [:avg, :average, :average_number]},
68
- sum_number: {aliases: [:sum]},
69
- strip: {aliases: [:trim]},
70
- # rename: { aliases: [:rename_key]},
71
- concat: { aliases: [:join, :concat_with]},
72
- reverse_concat: { aliases: [:reverse_join, :reverse_concat_with]}
39
+ evaluate: { aliases: [:eval, :equation, :equate]},
40
+ append: { aliases: [:suffix]},
41
+ prepend: { aliases: [:prefix]},
42
+ split: { aliases: [:delimit, :delim, :separate, :msplit]},
43
+ replace: { aliases: [:swap]},
44
+ extract: { aliases: [:grab, :scan]},
45
+ extract_first: { aliases: [:grab_first, :scan_first]},
46
+ extract_last: { aliases: [:grab_last, :scan_last]},
47
+ parse_date: { aliases: [:date, :parse_time, :time]},
48
+ parse_date_unix: { aliases: [:unix_time, :unix_date]},
49
+ parse_duration: { aliases: [:duration]},
50
+ parse_file_size: { aliases: [:file_size]},
51
+ to_string: { aliases: [:to_s, :stringify]},
52
+ downcase: { aliases: [:lower, :lowercase, :to_lower]},
53
+ upcase: { aliases: [:upper, :uppercase, :to_upper]},
54
+ roman: { aliases: [:convert_roman, :roman_numeral, :parse_roman]},
55
+ remove_symbols: { aliases: [:chop_symbols, :drop_symbols]},
56
+ format_articles: { aliases: [:articles]},
57
+ reverse: { aliases: [:invert]},
58
+ delete: { aliases: [:del]},
59
+ remove: { aliases: [:rem]},
60
+ custom: { aliases: [:send]},
61
+ encapsulate: { aliases: []},
62
+ uncapsulate: {aliases: []},
63
+ extract_integers: { aliases: [:extract_ints]},
64
+ extract_floats: { aliases: []},
65
+ extract_numbers: { aliases: []},
66
+ max_number: { aliases: [:max, :maximum, :maximum_number]},
67
+ min_number: { aliases: [:min, :minimum, :minimum_number]},
68
+ avg_number: { aliases: [:avg, :average, :average_number]},
69
+ sum_number: { aliases: [:sum]},
70
+ strip: { aliases: [:trim]},
71
+ concat: { aliases: [:join, :concat_with]},
72
+ reverse_concat: { aliases: [:reverse_join, :reverse_concat_with]}
73
73
  }
74
74
 
75
75
  module HashPath
76
76
 
77
- def self.evaluate hash, path, value, args, params
77
+ def self.evaluate hash, path, value, args
78
78
  exp = args.to_a.first.to_s.gsub('$', value.to_s)
79
79
  hash.hash_path_set path => eval(exp)
80
80
  end
81
81
 
82
- def self.append hash, path, value, args, params
82
+ def self.append hash, path, value, args
83
83
  hash.hash_path_set path => "#{value}#{args}"
84
84
  end
85
85
 
86
- def self.prepend hash, path, value, args, params
86
+ def self.prepend hash, path, value, args
87
87
  hash.hash_path_set path => "#{args}#{value}"
88
88
  end
89
89
 
90
- def self.split hash, path, value, args, params
90
+ def self.split hash, path, value, args
91
91
  hash.hash_path_set path => value.msplit(args)
92
92
  end
93
93
 
94
- def self.replace hash, path, value, args, params
94
+ def self.replace hash, path, value, args
95
95
  value = value.dup.to_s
96
96
  args.each{ |k,v| value.gsub!(k, v.to_s) }
97
97
  hash.hash_path_set path => value
98
98
  end
99
99
 
100
- def self.extract hash, path, value, *args, **params
100
+ def self.extract hash, path, value, *args
101
101
  slice = (Array === args && args[1].nil? ? (0..-1) : args[1])
102
102
  hash.hash_path_set path => value.to_s.scan(args.first)[slice]
103
103
  end
104
104
 
105
- def self.extract_first hash, path, value, *args, **params
105
+ def self.extract_first hash, path, value, *args
106
106
  extract(hash, path, value, *args + [0])
107
107
  end
108
108
 
109
- def self.extract_last hash, path, value, *args, **params
109
+ def self.extract_last hash, path, value, *args
110
110
  extract(hash, path, value, *args + [-1])
111
111
  end
112
112
 
113
- def self.parse_date hash, path, value, *args, **params
113
+ def self.parse_date hash, path, value, *args
114
+ params = BBLib::named_args(args)
114
115
  format = params.include?(:format) ? params[:format] : '%Y-%m-%d %H:%M:%S'
115
116
  formatted = nil
116
117
  args.each do |pattern|
@@ -127,7 +128,8 @@ module BBLib
127
128
  hash.hash_path_set path => formatted
128
129
  end
129
130
 
130
- def self.parse_date_unix hash, path, value, *args, **params
131
+ def self.parse_date_unix hash, path, value, *args
132
+ params = BBLib::named_args(args)
131
133
  format = params.include?(:format) ? params[:format] : '%Y-%m-%d %H:%M:%S'
132
134
  formatted = nil
133
135
  args.each do |pattern|
@@ -144,110 +146,108 @@ module BBLib
144
146
  hash.hash_path_set path => formatted.to_f
145
147
  end
146
148
 
147
- def self.parse_duration hash, path, value, args, params
149
+ def self.parse_duration hash, path, value, args
148
150
  hash.hash_path_set path => value.to_s.parse_duration(output: args.empty? ? :sec : args )
149
151
  end
150
152
 
151
- def self.parse_file_size hash, path, value, args, params
153
+ def self.parse_file_size hash, path, value, args
152
154
  hash.hash_path_set path => value.to_s.parse_file_size(output: args.empty? ? :bytes : args )
153
155
  end
154
156
 
155
- def self.to_string hash, path, value, *args, **params
157
+ def self.to_string hash, path, value, *args
156
158
  hash.hash_path_set path => value.to_s
157
159
  end
158
160
 
159
- def self.downcase hash, path, value, *args, **params
161
+ def self.downcase hash, path, value, *args
160
162
  hash.hash_path_set path => value.to_s.downcase
161
163
  end
162
164
 
163
- def self.upcase hash, path, value, *args, **params
165
+ def self.upcase hash, path, value, *args
164
166
  hash.hash_path_set path => value.to_s.upcase
165
167
  end
166
168
 
167
- def self.roman hash, path, value, *args, **params
169
+ def self.roman hash, path, value, *args
168
170
  hash.hash_path_set path => (args[0] == :to ? value.to_s.to_roman : value.to_s.from_roman)
169
171
  end
170
172
 
171
- def self.remove_symbols hash, path, value, *args, **params
173
+ def self.remove_symbols hash, path, value, *args
172
174
  hash.hash_path_set path => value.to_s.drop_symbols
173
175
  end
174
176
 
175
- def self.format_articles hash, path, value, args, **params
177
+ def self.format_articles hash, path, value, args
176
178
  hash.hash_path_set path => value.to_s.move_articles(args.nil? ? :front : args)
177
179
  end
178
180
 
179
- def self.reverse hash, path, value, *args, **params
181
+ def self.reverse hash, path, value, *args
180
182
  hash.hash_path_set path => value.to_s.reverse
181
183
  end
182
184
 
183
- def self.delete hash, path, value, *args, **params
185
+ def self.delete hash, path, value, *args
184
186
  hash.hash_path_delete path
185
187
  end
186
188
 
187
- def self.remove hash, path, value, *args, **params
189
+ def self.remove hash, path, value, *args
188
190
  removed = value.to_s
189
191
  args.each{ |a| removed.gsub!(a, '')}
190
192
  hash.hash_path_set path => removed
191
193
  end
192
194
 
193
- def self.custom hash, path, value, *args, **params
194
- if params.nil? || params.empty?
195
- hash.hash_path_set path => value.send(*args)
196
- else
197
- hash.hash_path_set path => value.send(*args, **params)
198
- end
195
+ def self.custom hash, path, value, *args
196
+ hash.hash_path_set path => value.send(*args)
199
197
  end
200
198
 
201
- def self.encapsulate hash, path, value, args, **params
199
+ def self.encapsulate hash, path, value, args
202
200
  hash.hash_path_set path => "#{args}#{value}#{args}"
203
201
  end
204
202
 
205
- def self.uncapsulate hash, path, value, args, **params
203
+ def self.uncapsulate hash, path, value, args
206
204
  value = value[args.size..-1] if value.start_with?(args)
207
205
  value = value[0..-(args.size)-1] if value.end_with?(args)
208
206
  hash.hash_path_set path => value
209
207
  end
210
208
 
211
- def self.max_number hash, path, value, *args, **params
209
+ def self.max_number hash, path, value, *args
212
210
  hash.hash_path_set path => value.to_s.extract_numbers.max
213
211
  end
214
212
 
215
- def self.min_number hash, path, value, *args, **params
213
+ def self.min_number hash, path, value, *args
216
214
  hash.hash_path_set path => value.to_s.extract_numbers.min
217
215
  end
218
216
 
219
- def self.avg_number hash, path, value, *args, **params
217
+ def self.avg_number hash, path, value, *args
220
218
  nums = value.to_s.extract_numbers
221
219
  avg = nums.inject{ |s, x| s + x }.to_f / nums.size.to_f
222
220
  hash.hash_path_set path => avg
223
221
  end
224
222
 
225
- def self.sum_number hash, path, value, *args, **params
223
+ def self.sum_number hash, path, value, *args
226
224
  hash.hash_path_set path => value.to_s.extract_numbers.inject{ |s,x| s + x }
227
225
  end
228
226
 
229
- def self.strip hash, path, value, args, **params
227
+ def self.strip hash, path, value, args
230
228
  value.map!{ |m| m.respond_to?(:strip) ? m.strip : m } if value.is_a?(Array)
231
229
  hash.hash_path_set path => (value.respond_to?(:strip) ? value.strip : value)
232
230
  end
233
231
 
234
- def self.extract_integers hash, path, value, args, **params
232
+ def self.extract_integers hash, path, value, args
235
233
  hash.hash_path_set path => (value.extract_integers)
236
234
  end
237
235
 
238
- def self.extract_floats hash, path, value, args, **params
236
+ def self.extract_floats hash, path, value, args
239
237
  hash.hash_path_set path => (value.extract_floats)
240
238
  end
241
239
 
242
- def self.extract_numbers hash, path, value, args, **params
240
+ def self.extract_numbers hash, path, value, args
243
241
  hash.hash_path_set path => (value.extract_numbers)
244
242
  end
245
243
 
246
- def self.concat hash, path, value, *args, **params
244
+ def self.concat hash, path, value, *args
245
+ params = BBLib::named_args(args)
247
246
  hash.hash_path_set path => "#{value}#{params[:join]}#{hash.hash_path(args.first)[params[:range].nil? ? 0 : params[:range]]}"
248
247
  end
249
248
 
250
- def self.reverse_concat hash, path, value, *args, **params
249
+ def self.reverse_concat hash, path, value, *args
250
+ params = BBLib::named_args(args)
251
251
  hash.hash_path_set path => "#{hash.hash_path(args.first)[params[:range].nil? ? 0 : params[:range]]}#{params[:join]}#{value}"
252
252
  end
253
253
 
@@ -0,0 +1,81 @@
1
+
2
+ # This module provides similar functionality as hash path, but instead
3
+ # generates a PathHash object which wraps a Hash or Array. Elements may
4
+ # be accessed via method calls rather than path strings.
5
+
6
+ module BBLib
7
+
8
+ def self.path_hash hash
9
+ PathHash.new(hash)
10
+ end
11
+
12
+ class PathHash < BasicObject
13
+ attr_reader :hash, :recursive
14
+
15
+ def initialize hash
16
+ @hash = hash
17
+ end
18
+
19
+ def [] val
20
+ PathHash.new(@hash.map{ |h| h[val]} )
21
+ end
22
+
23
+ def _val
24
+ @hash
25
+ end
26
+
27
+ alias_method :_v, :_val
28
+
29
+ def _fval
30
+ @hash.first rescue @hash
31
+ end
32
+
33
+ alias_method :_f, :_fval
34
+
35
+ def _
36
+ @recursive = true
37
+ self
38
+ end
39
+
40
+ def _path arg, formula = nil
41
+ method_missing arg, formula
42
+ end
43
+
44
+ private
45
+
46
+ def method_missing arg, formula = nil
47
+ arg = (@recursive ? "..#{arg}" : arg.to_s) +
48
+ (formula ? "(#{formula})" : '')
49
+ if @hash.is_a?(::Array)
50
+ PathHash.new @hash.map{ |h| if h.is_a?(::Array) || h.is_a?(::Hash) then h.hash_path(arg) end }.flatten(1)
51
+ else
52
+ PathHash.new @hash.hpath(arg)
53
+ end
54
+ end
55
+
56
+ end
57
+
58
+ end
59
+
60
+
61
+ class Hash
62
+
63
+ def path_hash
64
+ BBLib::path_hash(self)
65
+ end
66
+
67
+ alias_method :phash, :path_hash
68
+ alias_method :_ph, :path_hash
69
+
70
+ end
71
+
72
+ class Array
73
+
74
+ def path_hash
75
+ BBLib::path_hash(self)
76
+ end
77
+
78
+ alias_method :phash, :path_hash
79
+ alias_method :_ph, :path_hash
80
+
81
+ end
@@ -0,0 +1,182 @@
1
+ module BBLib::Attr
2
+
3
+ private
4
+
5
+ def attr_type method, opts, &block
6
+ define_method("#{method}=", &block)
7
+ define_method(method){ instance_variable_get("@#{method}")}
8
+ if defined?(:before) && opts.include?(:default)
9
+ define_method("__reset_#{method}".to_sym){ send("#{method}=", opts[:default]) }
10
+ end
11
+ end
12
+
13
+ def attr_sender call, *methods, **opts
14
+ methods.each do |m|
15
+ attr_type(
16
+ m,
17
+ opts,
18
+ &attr_set(
19
+ m,
20
+ opts.merge(sender: true)
21
+ ){ |x| x.nil? && opts[:allow_nil] ? nil : x.send(call) }
22
+ )
23
+ end
24
+ end
25
+
26
+ def attr_of klass, *methods, **opts
27
+ methods.each{ |m| attr_type(m, opts, &attr_set(m, opts){ |x|
28
+ if x.is_a?(klass)
29
+ instance_variable_set("@#{m}", x)
30
+ else
31
+ raise ArgumentError, "#{method} must be set to a #{klass}!"
32
+ end
33
+ }
34
+ )
35
+ }
36
+ end
37
+
38
+ def attr_boolean *methods, **opts
39
+ methods.each{ |m|
40
+ attr_type(m, opts) { |x| instance_variable_set("@#{m}", !!x && x.to_s != 'false') }
41
+ alias_method "#{m}?", m unless opts[:no_q]
42
+ }
43
+ end
44
+
45
+ alias_method :attr_bool, :attr_boolean
46
+
47
+ def attr_string *methods, **opts
48
+ attr_sender :to_s, *methods, opts
49
+ end
50
+
51
+ alias_method :attr_str, :attr_string
52
+ alias_method :attr_s, :attr_string
53
+
54
+ def attr_integer *methods, **opts
55
+ attr_sender :to_i, *methods, opts
56
+ end
57
+
58
+ alias_method :attr_int, :attr_integer
59
+ alias_method :attr_i, :attr_integer
60
+
61
+ def attr_float *methods, **opts
62
+ attr_sender :to_f, *methods, opts
63
+ end
64
+
65
+ alias_method :attr_f, :attr_float
66
+
67
+ def attr_integer_between min, max, *methods, **opts
68
+ methods.each{ |m| attr_type(m, opts, &attr_set(m, opts){ |x| BBLib::keep_between(x, min, max) })}
69
+ end
70
+
71
+ alias_method :attr_int_between, :attr_integer_between
72
+ alias_method :attr_i_between, :attr_integer_between
73
+ alias_method :attr_float_between, :attr_integer_between
74
+ alias_method :attr_f_between, :attr_float_between
75
+
76
+ def attr_symbol *methods, **opts
77
+ methods.each{ |m| attr_type(m, opts, &attr_set(m, opts){ |x| x.to_s.to_sym } )}
78
+ end
79
+
80
+ alias_method :attr_sym, :attr_symbol
81
+
82
+ def attr_clean_symbol *methods, **opts
83
+ methods.each{ |m| attr_type(m, opts, &attr_set(m, opts){ |x| x.to_s.to_clean_sym } )}
84
+ end
85
+
86
+ alias_method :attr_clean_sym, :attr_clean_symbol
87
+
88
+ def attr_array *methods, **opts
89
+ methods.each{ |m| attr_type(m, opts, &attr_set(m, opts){ |*x| instance_variable_set("@#{m}", x) } )}
90
+ end
91
+
92
+ alias_method :attr_ary, :attr_array
93
+
94
+ def attr_element_of list, *methods, **opts
95
+ methods.each do |m|
96
+ attr_type(m, opts, &attr_set(m, opts) do |x|
97
+ if !list.include?(x)
98
+ raise ArgumentError, "#{m} only accepts the following (first 10 shown) #{list[0...10]}"
99
+ else
100
+ instance_variable_set("@#{m}", x)
101
+ end
102
+ end
103
+ )
104
+ end
105
+ end
106
+
107
+ def attr_array_of klass, *methods, raise: false, **opts
108
+ methods.each do |m|
109
+ attr_type(m, opts, &attr_set(m, opts) do |*x|
110
+ if raise && x.any?{ |i| klass.is_a?(Array) ? !klass.any?{ |k| i.is_a?(k) } : !i.is_a?(klass) }
111
+ raise ArgumentError, "#{m} only accepts items of class #{klass}."
112
+ end
113
+ instance_variable_set("@#{m}", x.reject{|i| klass.is_a?(Array) ? !klass.any?{ |k| i.is_a?(k) } : !i.is_a?(klass) })
114
+ end
115
+ )
116
+ end
117
+ end
118
+
119
+ alias_method :attr_ary_of, :attr_array_of
120
+
121
+ def attr_hash *methods, **opts
122
+ methods.each{ |m| attr_type(m, opts, &attr_set(m, opts) do |*a|
123
+ begin
124
+ hash = a.find_all{ |i| i.is_a?(Hash) }.inject({}){ |m, h| m.merge(h) } || Hash.new
125
+ instance_variable_set("@#{m}", hash)
126
+ rescue ArgumentError => e
127
+ raise ArgumentError, "#{m} only accepts a hash for its parameters"
128
+ end
129
+ end
130
+ )
131
+ }
132
+ end
133
+
134
+ def attr_valid_file *methods, raise: true, **opts
135
+ methods.each{ |m| attr_type(m, opts, &attr_set(m, opts){ |x| File.exists?(x.to_s) ? x.to_s : (raise ? raise(ArgumentError, "File '#{x}' does not exist. @#{m} must be set to a valid file location!") : nil)} )}
136
+ end
137
+
138
+ def attr_valid_dir *methods, raise: true, **opts
139
+ methods.each{ |m| attr_type(m, opts, &attr_set(m, opts){ |x| Dir.exists?(x.to_s) ? x.to_s : (raise ? raise(ArgumentError, "Dir '#{x}' does not exist. @#{m} must be set to a valid directory location!") : nil)} )}
140
+ end
141
+
142
+ def attr_time *methods, **opts
143
+ methods.each do |m|
144
+ attr_type(
145
+ m,
146
+ opts,
147
+ &attr_set(m, opts){ |x|
148
+ if x.is_a?(Time) || x.nil? && opt[:allow_nil]
149
+ x
150
+ elsif x.is_a?(Numeric)
151
+ Time.at(x)
152
+ elsif x.is_a?(String)
153
+ Time.parse(x)
154
+ else
155
+ raise "#{x} is an invalid Time object and could not be converted into a Time object."
156
+ end
157
+ }
158
+ )
159
+ end
160
+ end
161
+
162
+ def attr_set method, allow_nil: false, fallback: :_nil, sender: false, default: nil, &block
163
+ proc{ |x|
164
+ if x.nil? && !allow_nil && fallback == :_nil && !sender
165
+ raise ArgumentError, "#{method} cannot be set to nil!"
166
+ elsif x.nil? && !allow_nil && fallback != :_nil && !sender
167
+ instance_variable_set("@#{method}", fallback)
168
+ else
169
+ begin
170
+ instance_variable_set("@#{method}", x.nil? && !sender ? x : yield(x) )
171
+ rescue Exception => e
172
+ if fallback != :_nil
173
+ instance_variable_set("@#{method}", fallback)
174
+ else
175
+ raise e
176
+ end
177
+ end
178
+ end
179
+ }
180
+ end
181
+
182
+ end