qualitysmith_extensions 0.0.20 → 0.0.24

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,97 @@
1
+ #--
2
+ # Author:: Tyler Rick
3
+ # Copyright:: Copyright (c) 2007 QualitySmith, Inc.
4
+ # License:: Ruby License
5
+ # Submit to Facets?:: Yes!
6
+ # Developer notes:
7
+ # * This is the analog in Array to Set#classify (core).
8
+ # * Compare to Array#group_by (qualitysmith_extensions), which assumes all elements are arrays (making a "table") and only
9
+ # allows you to do simple classification by the value of a "column". On the other hand, it adds the option to delete that
10
+ # column from the array, which can be nice, since the classification key in the hash makes it somewhat redundant.
11
+ #++
12
+
13
+ require 'rubygems'
14
+ gem 'facets'
15
+ require 'facet/array/to_hash'
16
+ class Array
17
+
18
+ =begin rdoc
19
+ Classifies the array by the return value of the given block and returns a hash of {value => array of elements} pairs.
20
+ The block is called once for each element of the array, passing the element as parameter.
21
+
22
+ Breaks an array into a hash of smaller arrays, making a new group for each unique value returned by the block. Each unique value becomes a key in the hash.
23
+
24
+ Example:
25
+ [
26
+ ['a', 1],
27
+ ['a', 2],
28
+ ['b', 3],
29
+ ['b', 4],
30
+ ].classify {|o| o[0]}
31
+ =>
32
+ {
33
+ "a" => [['a', 1], ['a', 2]],
34
+ "b" => [['b', 3], ['b', 4]]
35
+ }
36
+ =end
37
+ def classify(&block)
38
+ hash = {}
39
+ each do |element|
40
+ classification = yield(element)
41
+ (hash[classification] ||= []) << element
42
+ end
43
+ hash
44
+ end
45
+ end
46
+
47
+ # _____ _
48
+ # |_ _|__ ___| |_
49
+ # | |/ _ \/ __| __|
50
+ # | | __/\__ \ |_
51
+ # |_|\___||___/\__|
52
+ #
53
+ =begin test
54
+ require 'set'
55
+
56
+ class TheTest < Test::Unit::TestCase
57
+ def test_classify
58
+ input = [
59
+ ['a', 1],
60
+ ['a', 2],
61
+ ['b', 3],
62
+ ['b', 4],
63
+ ]
64
+ assert_equal({
65
+ "a" => [['a', 1], ['a', 2]],
66
+ "b" => [['b', 3], ['b', 4]]
67
+ }, input.classify {|o| o[0]}
68
+ )
69
+ # For comparison:
70
+ assert_equal({
71
+ "a" => Set[['a', 1], ['a', 2]],
72
+ "b" => Set[['b', 3], ['b', 4]]
73
+ }, input.to_set.classify {|o| o[0]}
74
+ )
75
+
76
+
77
+ input = [
78
+ ['Bob', "Bottle of water", 1.00],
79
+ ['Bob', "Expensive stapler", 50.00],
80
+ ['Alice', "Dinner for 2", 100.00],
81
+ ['Alice', "Bus ride to RubyConf", 50.00],
82
+ ]
83
+ assert_equal({
84
+ "Alice" => [['Alice',"Dinner for 2", 100.0], ['Alice', "Bus ride to RubyConf", 50.0]],
85
+ "Bob" => [['Bob', "Bottle of water", 1.0], ['Bob', "Expensive stapler", 50.0]]
86
+ }, input.classify {|o| o[0]}
87
+ )
88
+ assert_equal({
89
+ 50.0 => [["Bob", "Expensive stapler", 50.00], ["Alice", "Bus ride to RubyConf", 50.00]],
90
+ 100.0 => [["Alice", "Dinner for 2", 100.00]],
91
+ 1.0 => [["Bob", "Bottle of water", 1.00]]
92
+ }, input.classify {|o| o[2]}
93
+ )
94
+ end
95
+ end
96
+ =end
97
+
@@ -2,19 +2,22 @@
2
2
  # Author:: Tyler Rick
3
3
  # Copyright:: Copyright (c) 2007 QualitySmith, Inc.
4
4
  # License:: Ruby License
5
- # Submit to Facets?:: Yes
5
+ # Submit to Facets?:: Maybe.
6
6
  # Developer notes:
7
7
  # * Name is too general? Name it something to do with 'tables'?
8
+ # * group_table_by ?
9
+ # * Compare to Array#classify (qualitysmith_extensions), which aims to be more general, letting you classify arrays that are
10
+ # *not* in "table" form (whose elements are *not* all arrays of equal size and might not even be *arrays*).
8
11
  #++
9
12
 
10
13
  require 'rubygems'
11
14
  gem 'facets'
12
15
  require 'facet/array/delete_values_at'
13
- require 'facet/array/to_hash'
14
16
  class Array
15
17
 
16
18
  =begin rdoc
17
- Breaks an array into a hash of smaller arrays, making a new group for each unique value in the specified column. Each unique value becomes a key in the hash.
19
+ Breaks an array into a hash of smaller arrays, making a new group for each unique value in the specified column.
20
+ Each unique value becomes a key in the hash.
18
21
 
19
22
  Example:
20
23
  [
@@ -42,7 +45,8 @@ class Array
42
45
  "b"=>[['b', 3], ['b', 4]]
43
46
 
44
47
  *Notes*:
45
- * <tt>self</tt> must be in the shape of a "table" (a non-sparse, rectangular, two-dimensional array).
48
+ * <tt>self</tt> must be in the shape of a "table" (that is, a rectangular-shaped, two-dimensional array = an array of arrays,
49
+ each member array being of the same size (the "width" of the table)).
46
50
  * This is different from the GROUP BY in SQL in that it doesn't apply an aggregate (like sum or average) to each group -- it just returns each group unmodified.
47
51
 
48
52
  =end
@@ -67,6 +71,8 @@ end
67
71
  # |_|\___||___/\__|
68
72
  #
69
73
  =begin test
74
+ require 'set'
75
+
70
76
  class TheTest < Test::Unit::TestCase
71
77
  def test_group_by
72
78
  assert_equal({ }, [ ].group_by(column_index = 0))
@@ -81,6 +87,9 @@ class TheTest < Test::Unit::TestCase
81
87
  ['b', 4],
82
88
  ].group_by(column_index = 0)
83
89
  )
90
+
91
+
92
+
84
93
  assert_equal({
85
94
  "a"=>[['a', 1], ['a', 2]],
86
95
  "b"=>[['b', 3], ['b', 4]]
@@ -91,6 +100,17 @@ class TheTest < Test::Unit::TestCase
91
100
  ['b', 4],
92
101
  ].group_by(column_index = 0, :delete_key => false)
93
102
  )
103
+ assert_equal({
104
+ "a" => Set[['a', 1], ['a', 2]],
105
+ "b" => Set[['b', 3], ['b', 4]]
106
+ }, [
107
+ ['a', 1],
108
+ ['a', 2],
109
+ ['b', 3],
110
+ ['b', 4],
111
+ ].to_set.classify {|o| o[0]}
112
+ )
113
+
94
114
 
95
115
  input = [
96
116
  ['Bob', "Bottle of water", 1.00],
@@ -0,0 +1,61 @@
1
+ #--
2
+ # Author:: Tyler Rick
3
+ # Copyright:: Copyright (c) 2007 QualitySmith, Inc.
4
+ # License:: Ruby License
5
+ # Submit to Facets?::
6
+ # Developer notes::
7
+ #++
8
+
9
+ require 'rubygems'
10
+ gem 'colored'
11
+ require 'colored'
12
+ gem 'facets'
13
+ require 'facets/core/module/alias_method_chain'
14
+ gem 'qualitysmith_extensions'
15
+ require 'qualitysmith_extensions/module/guard_method'
16
+
17
+ class String
18
+ def colorize_with_toggleability(string, options = {})
19
+ if @@colorize_enabled
20
+ colorize_without_toggleability(string, options)
21
+ else
22
+ string
23
+ end
24
+ end
25
+ alias_method_chain :colorize, :toggleability
26
+ mguard_method :color_on!, :@@colorize_enabled, :color_off!
27
+
28
+ end unless String.instance_methods.include?('colorize_with_toggleability')
29
+
30
+
31
+ # _____ _
32
+ # |_ _|__ ___| |_
33
+ # | |/ _ \/ __| __|
34
+ # | | __/\__ \ |_
35
+ # |_|\___||___/\__|
36
+ #
37
+ =begin test
38
+ require 'test/unit'
39
+
40
+ class TheTest < Test::Unit::TestCase
41
+ def test_color_on!
42
+ String.color_on!
43
+ assert_equal "\e[31mfoo\e[0m", 'foo'.red
44
+ end
45
+ def test_color_off!
46
+ String.color_off!
47
+ assert_equal "foo", 'foo'.red
48
+ end
49
+ def test_color_off_with_block
50
+ String.color_on!
51
+ assert_equal "\e[31mfoo\e[0m", 'foo'.red
52
+ String.color_off! do
53
+ assert_equal "foo", 'foo'.red
54
+ end
55
+ assert_equal "\e[31mfoo\e[0m", 'foo'.red
56
+ end
57
+
58
+ end
59
+ =end
60
+
61
+
@@ -0,0 +1,414 @@
1
+ #--
2
+ # Author:: Thomas Sawyer, Tyler Rick
3
+ # Copyright:: Copyright (c) Thomas Sawyer, probably, since this is a derivative work
4
+ # License:: Ruby License
5
+ # Submit to Facets?:: Yes
6
+ # Developer notes::
7
+ # * Based on /usr/lib/ruby/gems/1.8/gems/facets-1.8.54/lib/facets/core/module/attr_tester.rb
8
+ # * Hey Thomas, don't you think Module#attr_tester should only create the read-only a? method and have another method that creates the writer (like there how we have attr_reader, _writer, and _accessor?) ? "tester" does not imply "setter" in my mind...
9
+ # * I'm going to rename this one to bool_attr_accessor, which calls both bool_attr_reader and bool_attr_writer
10
+ # * Then you also have the option to use bool_attr_reader and bool_attr_writer separately if you so desire.
11
+ # * Other changes made:
12
+ # * Changed it so that if you call a!(false) it would actually set @a to false rather than leaving it unchanged. (I assume that was a bug.)
13
+ #++
14
+
15
+ # bool_attr_accessor
16
+
17
+ class Module
18
+ # This creates a reader method for a boolean (flag) attribute (instance variable).
19
+ #
20
+ # bool_attr_reader :a
21
+ #
22
+ # is equivalent to
23
+ #
24
+ # def a?
25
+ # @a ? true : @a
26
+ # end
27
+ #
28
+ # Example:
29
+ # class Foo
30
+ # def set_it
31
+ # @a = true
32
+ # end
33
+ # end
34
+ # x = Foo.new
35
+ # x.a? # => false
36
+ # x.set_it
37
+ # x.a? # => true
38
+ #
39
+ def bool_attr_reader(*args)
40
+ make = {}
41
+ args.each { |a|
42
+ make["#{a}?".to_sym] = %{
43
+ def #{a}?(true_value=true)
44
+ @#{a} ? true_value : @#{a}
45
+ end
46
+ }
47
+ }
48
+ module_eval make.values.join("\n"), __FILE__, __LINE__
49
+
50
+ make.keys
51
+ end
52
+
53
+ # This creates a setter method for a boolean (flag) attribute (instance variable).
54
+ #
55
+ # bool_attr_setter :a
56
+ #
57
+ # is equivalent to
58
+ #
59
+ # def a!(switch=Exception)
60
+ # if switch == Exception
61
+ # @a = !@a
62
+ # else
63
+ # @a = switch ? true : false
64
+ # self
65
+ # end
66
+ # end
67
+ #
68
+ # This setter method can either be used to set it directly to true or false or to toggle it.
69
+ #
70
+ # Examples:
71
+ # x = Klass.new
72
+ # x.a! true # sets @a to true
73
+ # x.a! # toggles @a, so that it ends up being false
74
+ # x.a! # toggles @a, so that it ends up being true
75
+ # x.a! false # sets @a to false
76
+ #
77
+ def bool_attr_setter(*args)
78
+ make = {}
79
+ args.each { |a|
80
+ make["#{a}!".to_sym] = %{
81
+ def #{a}!(switch=Exception)
82
+ if switch == Exception
83
+ @#{a} = !@#{a}
84
+ else
85
+ @#{a} = switch ? true : false
86
+ # used to be @#{a} instead of false in Facets version
87
+ self
88
+ end
89
+ end
90
+ }
91
+ }
92
+ module_eval make.values.join("\n"), __FILE__, __LINE__
93
+ make.keys
94
+ end
95
+
96
+
97
+ # This creates both a reader and a setter for a boolean (flag) attribute (instance variable).
98
+ #
99
+ # bool_attr_accessor :a
100
+ #
101
+ # is equivalent to
102
+ #
103
+ # bool_attr_reader :a
104
+ # bool_attr_setter :a
105
+ #
106
+ # Examples:
107
+ # x = Klass.new
108
+ # x.a! true # sets @a to true
109
+ # x.a? # => true
110
+ # x.a! # toggles @a, so that it ends up being false
111
+ # x.a! # toggles @a, so that it ends up being true
112
+ # x.a! false # sets @a to false
113
+ #
114
+ def bool_attr_accessor(*args)
115
+ bool_attr_reader *args
116
+ bool_attr_setter *args
117
+ end
118
+
119
+ end
120
+
121
+ # mbool_attr_accessor
122
+
123
+ class Module
124
+ # This creates a reader method for a boolean (flag) class/module variable.
125
+ #
126
+ # mbool_attr_reader :a
127
+ #
128
+ # is equivalent to
129
+ #
130
+ # def self.a?
131
+ # @@a ? true : @@a
132
+ # end
133
+ #
134
+ # Works for both classes and modules.
135
+ #
136
+ def mbool_attr_reader(*args)
137
+ make = {}
138
+ args.each { |a|
139
+ make["#{a}?".to_sym] = %{
140
+ def self.#{a}?(true_value=true)
141
+ @@#{a} ? true_value : @@#{a}
142
+ end
143
+ }
144
+ }
145
+ module_eval make.values.join("\n"), __FILE__, __LINE__
146
+ make.keys
147
+ end
148
+
149
+ # This creates a setter method for a boolean (flag) class/module variable.
150
+ #
151
+ # mbool_attr_setter :a
152
+ #
153
+ # is equivalent to
154
+ #
155
+ # def self.a!(switch=Exception)
156
+ # if switch == Exception
157
+ # @@a = !@@a
158
+ # else
159
+ # @@a = switch ? true : false
160
+ # self
161
+ # end
162
+ # end
163
+ #
164
+ # Works for both classes and modules.
165
+ #
166
+ def mbool_attr_setter(*args)
167
+ make = {}
168
+ args.each { |a|
169
+ # Initialize it first so that we won't have any NameErrors.
170
+ module_eval %{ @@#{a} = nil if !defined?(@@#{a}) }, __FILE__, __LINE__
171
+
172
+ make["#{a}!".to_sym] = %{
173
+ def self.#{a}!(switch=Exception)
174
+ if switch == Exception
175
+ @@#{a} = !@@#{a}
176
+ else
177
+ @@#{a} = switch ? true : false
178
+ self
179
+ end
180
+ end
181
+ }
182
+ }
183
+ module_eval make.values.join("\n"), __FILE__, __LINE__
184
+ make.keys
185
+ end
186
+
187
+ # This creates both a reader and a setter for a boolean (flag) class/module variable.
188
+ #
189
+ # mbool_attr_accessor :a
190
+ #
191
+ # is equivalent to
192
+ #
193
+ # mbool_attr_reader :a
194
+ # mbool_attr_setter :a
195
+ #
196
+ # Works for both classes and modules.
197
+ #
198
+ def mbool_attr_accessor(*args)
199
+ mbool_attr_reader :a
200
+ mbool_attr_setter :a
201
+ end
202
+ end
203
+
204
+
205
+
206
+ # _____ _
207
+ # |_ _|__ ___| |_
208
+ # | |/ _ \/ __| __|
209
+ # | | __/\__ \ |_
210
+ # |_|\___||___/\__|
211
+ #
212
+ =begin test
213
+ require 'test/unit'
214
+ require 'rubygems'
215
+ require 'qualitysmith_extensions/object/ignore_access'
216
+
217
+ # Test that it works for *instances*
218
+ class TestBoolAttr < Test::Unit::TestCase
219
+ def setup
220
+ @x = C.new
221
+ end
222
+
223
+ class C_for_default_is_nil
224
+ bool_attr_accessor :a, :b
225
+ end
226
+
227
+ # Also tests that it can create multiple accessors at once.
228
+ def test1_default_is_nil
229
+ assert_equal nil, C_for_default_is_nil.new.a?
230
+ assert_equal nil, C_for_default_is_nil.new.b?
231
+ end
232
+
233
+ class C
234
+ bool_attr_accessor :a
235
+ end
236
+
237
+ def test2_toggle
238
+ assert_equal nil, @x.a?
239
+ @x.a!
240
+ assert_equal true, @x.a?
241
+ @x.a!
242
+ assert_equal false, @x.a?
243
+ end
244
+
245
+ def test3_setter
246
+ @x.a! true
247
+ @x.a! true
248
+ assert_equal true, @x.a?
249
+
250
+ @x.a! false
251
+ assert_equal false, @x.a?
252
+ end
253
+ def test4_sets_to_boolean_even_if_try_to_set_to_other_type
254
+ @x.a! "whatever"
255
+ assert_equal true, @x.a? # Still returns a boolean even though we tried to set it to a string.
256
+
257
+ @x.a! nil
258
+ assert_equal false, @x.a? # Still returns a boolean even though we tried to set it to nil.
259
+ end
260
+ end
261
+
262
+ # Test that it works for *modules*
263
+ class TestForModules < Test::Unit::TestCase
264
+
265
+ class M_for_default_is_nil
266
+ mbool_attr_accessor :a
267
+ end
268
+ def test1_default_is_nil
269
+ assert_equal nil, M_for_default_is_nil.a?
270
+ end
271
+
272
+ module M
273
+ mbool_attr_accessor :a
274
+ end
275
+ def test2_toggle
276
+ assert_equal nil, M.a?
277
+ M.a!
278
+ assert_equal true, M.a?
279
+ M.a!
280
+ assert_equal false, M.a?
281
+ end
282
+ def test3_setter
283
+ M.a! true
284
+ M.a! true
285
+ assert_equal true, M.a?
286
+
287
+ M.a! false
288
+ assert_equal false, M.a?
289
+ end
290
+ def test4_sets_to_boolean_even_if_try_to_set_to_other_type
291
+ M.a! "whatever"
292
+ assert_equal true, M.a? # Still returns a boolean even though we tried to set it to a string.
293
+
294
+ M.a! nil
295
+ assert_equal false, M.a? # Still returns a boolean even though we tried to set it to nil.
296
+ end
297
+ end
298
+
299
+ # Test that it also works for *classes*
300
+ class TestForClasses < Test::Unit::TestCase
301
+
302
+ class C_for_default_is_nil
303
+ mbool_attr_accessor :a
304
+ end
305
+ def test1_default_is_nil
306
+ assert_equal nil, C_for_default_is_nil.a?
307
+ end
308
+
309
+ class C
310
+ mbool_attr_accessor :a
311
+ end
312
+
313
+ def test2_toggle
314
+ C.access.class_variable_set :@@a, false
315
+ assert_equal false, C.a? # otherwise would have been nil
316
+ C.a!
317
+ assert_equal true, C.a?
318
+ C.a!
319
+ assert_equal false, C.a?
320
+
321
+ assert_equal ["@_ignore_access_functor"], C.instance_variables
322
+ assert_equal ["@@a"], C.class_variables
323
+ end
324
+
325
+ def test3_setter
326
+ C.a! true
327
+ C.a! true
328
+ assert_equal true, C.a?
329
+
330
+ C.a! false
331
+ assert_equal false, C.a?
332
+ end
333
+ def test4_sets_to_boolean_even_if_try_to_set_to_other_type
334
+ C.a! "whatever"
335
+ assert_equal true, C.a? # Still returns a boolean even though we tried to set it to a string.
336
+
337
+ C.a! nil
338
+ assert_equal false, C.a? # Still returns a boolean even though we tried to set it to nil.
339
+ end
340
+ end
341
+
342
+
343
+ # Observation: You can also the normal bool_attr_accessor in conjunction with class << self.
344
+ # The methods generated seem to *behave* in the same way. Both techniques allow you to query the class, C.a?
345
+ # The only difference is in which *variables* are use to store the state:
346
+ # * class << self and the normal bool_attr_accessor:
347
+ # Stores the state in an instance variable for the *class*: @a
348
+ # * mbool_attr_accessor:
349
+ # Stores the state in a *class* variable: @@a
350
+ #
351
+ # Can someone explain to me the difference between class variables and instance variables of a class?
352
+ # It seems silly (confusing even!) to have both of them!
353
+ #
354
+ # My best explanation is that the fact that we can even *have* instance variables of a class does *not* mean it's a good idea
355
+ # to use them. It simply means that Matz made the language with as few arbitrary restrictions as possible. He made it
356
+ # technically *possible* to do a lot of things that it is probably not good practice to do... And one of those things is
357
+ # using instance variables of classes to store state information for that class.
358
+ #
359
+ # What do you think class variables are for? Exactly that! There's a *reason* we have both @a and @@a variables -- to
360
+ # *differentiate* between the two kinds of variables and keep programmers sane. So please don't blur the distinction and
361
+ # use the @a-type variable to do the job that @@a-type variables are for.
362
+ #
363
+ # Or am I missing something here?
364
+ #
365
+ class TestWith_class_self_and_plain_bool_attr_accessor < Test::Unit::TestCase
366
+
367
+ class C_for_default_is_nil
368
+ class << self
369
+ bool_attr_accessor :a
370
+ end
371
+ end
372
+ def test1_default_is_nil
373
+ assert_equal nil, C_for_default_is_nil.a?
374
+ end
375
+
376
+ class C
377
+ class << self
378
+ bool_attr_accessor :a
379
+ end
380
+ end
381
+ # This is where I spotted a class that uses this technique:
382
+ # * Test::Unit::Assertions::AssertionMessage
383
+
384
+ def test_2_toggle
385
+ assert_equal false, C.a? # Why isn't it nil like it is for the instance use case of bool_attr_accessor?
386
+ C.a!
387
+ assert_equal true, C.a?
388
+ C.a!
389
+ assert_equal false, C.a?
390
+
391
+ assert_equal ["@a"], C.instance_variables
392
+ assert_equal [], C.new.instance_variables # @a is an instance variable of the *class* *not* objects of the class -- weird!
393
+ assert_equal [], C.class_variables
394
+ end
395
+
396
+ def test3_setter
397
+ C.a! true
398
+ C.a! true
399
+ assert_equal true, C.a?
400
+
401
+ C.a! false
402
+ assert_equal false, C.a?
403
+ end
404
+ def test4_sets_to_boolean_even_if_try_to_set_to_other_type
405
+ C.a! "whatever"
406
+ assert_equal true, C.a? # Still returns a boolean even though we tried to set it to a string.
407
+
408
+ C.a! nil
409
+ assert_equal false, C.a? # Still returns a boolean even though we tried to set it to nil.
410
+ end
411
+
412
+ end
413
+ =end
414
+