bblib 0.2.2 → 0.3.0

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