quality_extensions 1.1.4 → 1.1.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. data/lib/Xfind_bug_test.rb +28 -0
  2. data/lib/quality_extensions/array/all_same.rb +40 -0
  3. data/lib/quality_extensions/array/delete_if_bang.rb +145 -0
  4. data/lib/quality_extensions/array/expand_ranges.rb +3 -53
  5. data/lib/quality_extensions/array/include_any_of.rb +23 -0
  6. data/lib/quality_extensions/array/justify.rb +305 -0
  7. data/lib/quality_extensions/array/{average.rb → mean.rb} +1 -1
  8. data/lib/quality_extensions/array/select_if_bang.rb +0 -0
  9. data/lib/quality_extensions/array/sum.rb +30 -0
  10. data/lib/quality_extensions/enumerable/all_same.rb +43 -0
  11. data/lib/quality_extensions/enumerable/group_by_and_map.rb +110 -0
  12. data/lib/quality_extensions/enumerable/select_bang.rb +49 -0
  13. data/lib/quality_extensions/enumerable/select_while.rb +337 -52
  14. data/lib/quality_extensions/enumerable/select_with_index.rb +145 -0
  15. data/lib/quality_extensions/hash/hash_select.rb +5 -2
  16. data/lib/quality_extensions/hash/merge_if.rb +48 -0
  17. data/lib/quality_extensions/kernel/example_printer.rb +10 -3
  18. data/lib/quality_extensions/kernel/require_all.rb +24 -8
  19. data/lib/quality_extensions/kernel/sleep_loudly.rb +108 -0
  20. data/lib/quality_extensions/kernel/uninterruptable.rb +22 -0
  21. data/lib/quality_extensions/matrix/indexable.rb +68 -0
  22. data/lib/quality_extensions/matrix/linked_vectors.rb +137 -0
  23. data/lib/quality_extensions/module/class_methods.rb +2 -0
  24. data/lib/quality_extensions/object/non.rb +12 -0
  25. data/lib/quality_extensions/pathname.rb +435 -7
  26. data/lib/quality_extensions/range_list.rb +222 -0
  27. data/lib/quality_extensions/safe_nil.rb +5 -3
  28. data/lib/quality_extensions/string/each_char_with_index.rb +1 -2
  29. data/lib/quality_extensions/string/integer_eh.rb +3 -0
  30. data/lib/quality_extensions/string/numeric_eh.rb +74 -0
  31. data/lib/quality_extensions/string/safe_in_comment.rb +38 -0
  32. data/lib/quality_extensions/string/safe_numeric_conversion.rb +102 -0
  33. data/lib/quality_extensions/string/shell_escape.rb +4 -4
  34. data/lib/quality_extensions/string/with_knowledge_of_color.rb +8 -0
  35. data/lib/quality_extensions/table.rb +116 -0
  36. data/lib/quality_extensions/template.rb +4 -5
  37. data/lib/quality_extensions/template.rb_test_unit.rb +33 -0
  38. data/lib/quality_extensions/test/difference_highlighting-minitest.rb +321 -0
  39. data/lib/quality_extensions/test/difference_highlighting-test_unit.rb +325 -0
  40. data/lib/quality_extensions/test/difference_highlighting.rb +6 -314
  41. data/lib/quality_extensions/timeout/countdown_timer.rb +1 -0
  42. data/lib/quality_extensions/vector/enumerable.rb +51 -0
  43. metadata +35 -5
@@ -0,0 +1,145 @@
1
+ #--
2
+ # Author:: Tyler Rick
3
+ # Inspired by: http://snippets.dzone.com/posts/show/3746 (ntk on Fri Mar 30 10:00:43 -0400 2007)
4
+ # Copyright:: Copyright (c) 2009, Tyler Rick
5
+ # License:: Ruby License
6
+ # Submit to Facets?:: Yes
7
+ # Developer notes::
8
+ # History::
9
+ #++
10
+
11
+ require 'facets/kernel/require_local'
12
+ require_local 'select_bang'
13
+
14
+ module Enumerable
15
+ # def reject!
16
+ # if self.is_a? Range
17
+ # to_a.reject! { yield }
18
+ # else
19
+ # raise NoMethodError
20
+ # end
21
+ # end
22
+
23
+ def select_with_index
24
+ index = -1
25
+ if block_given?
26
+ #select { |x| index += 1; yield(x, index) } # not hash friendly?
27
+ select { |*args| index += 1; yield(*(args + [index])) }
28
+ else
29
+ self
30
+ end
31
+ end
32
+
33
+ def select_with_index!
34
+ index = -1
35
+ if block_given?
36
+ select! { |x| index += 1; yield(x, index) }
37
+ else
38
+ self
39
+ end
40
+ end
41
+
42
+ def reject_with_index
43
+ index = -1
44
+ if block_given?
45
+ reject { |x| index += 1; yield(x, index) }
46
+ else
47
+ self
48
+ end
49
+ end
50
+
51
+ def reject_with_index!
52
+ index = -1
53
+ if block_given?
54
+ reject! { |x| index += 1; yield(x, index) }
55
+ else
56
+ self
57
+ end
58
+ end
59
+
60
+ end
61
+
62
+
63
+ # _____ _
64
+ # |_ _|__ ___| |_
65
+ # | |/ _ \/ __| __|
66
+ # | | __/\__ \ |_
67
+ # |_|\___||___/\__|
68
+ #
69
+ =begin test
70
+ require 'spec'
71
+
72
+ describe 'Enumerable#select_with_index' do
73
+ it 'select_with_index without a block, return self' do
74
+ ('a'..'e').select_with_index.should == ('a'..'e')
75
+ end
76
+
77
+ it 'reject_with_index without a block, return self' do
78
+ ('a'..'n').reject_with_index.should == ('a'..'n')
79
+ end
80
+
81
+ it 'select_with_index with i % 2 == 0' do
82
+ ('a'..'e').select_with_index { |x, i| x if i % 2 == 0 }.should == ["a", "c", "e"]
83
+ end
84
+
85
+ it 'reject_with_index with i % 2 == 0' do
86
+ ('a'..'n').reject_with_index { |x, i| x if i % 2 == 0 }.should == ["b", "d", "f", "h", "j", "l", "n"]
87
+ end
88
+ end
89
+
90
+ describe 'Enumerable#select_with_index!' do
91
+ it 'reject!' do
92
+ a = %w[a b c d]
93
+ a.reject! {|e| e =~ /[ab]/}
94
+ a.should == %w[c d]
95
+ end
96
+
97
+ it 'select!' do
98
+ a = %w[a b c d]
99
+ a.select! {|e| e =~ /[ab]/}
100
+ a.should == %w[a b]
101
+ end
102
+
103
+ it 'select_with_index! modifies receiver' do
104
+ a = %w[a b c d]
105
+ a.select_with_index! { |x, i| x if i % 2 == 0 }.should == a
106
+ a.should == %w[a c]
107
+ end
108
+
109
+ it 'reject_with_index! modifies receiver' do
110
+ a = %w[a b c d]
111
+ a.reject_with_index! { |x, i| x if i % 2 == 0 }.should == a
112
+ a.should == %w[b d]
113
+ end
114
+ end
115
+
116
+ describe 'Enumerable#select_with_index! with hashes' do
117
+ it 'reject!' do
118
+ pending
119
+ a = %w[a b c d]
120
+ a.reject! {|e| e =~ /[ab]/}
121
+ a.should == %w[c d]
122
+ end
123
+
124
+ it 'select!' do
125
+ pending
126
+ a = %w[a b c d]
127
+ a.select! {|e| e =~ /[ab]/}
128
+ a.should == %w[a b]
129
+ end
130
+
131
+ it 'select_with_index! modifies receiver' do
132
+ pending
133
+ a = %w[a b c d]
134
+ a.select_with_index! { |x, i| x if i % 2 == 0 }.should == a
135
+ a.should == %w[a c]
136
+ end
137
+
138
+ it 'reject_with_index! modifies receiver' do
139
+ pending
140
+ a = %w[a b c d]
141
+ a.reject_with_index! { |x, i| x if i % 2 == 0 }.should == a
142
+ a.should == %w[b d]
143
+ end
144
+ end
145
+ =end
@@ -2,11 +2,13 @@
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?:: No.
6
+ # Deprecated. Ruby 1.9 implements #select correctly.
6
7
  #++
7
8
 
8
9
  require "rubygems"
9
10
 
11
+ if RUBY_VERSION < '1.9'
10
12
  class Hash
11
13
  # call-seq:
12
14
  # hash.hash_select {| key, value | block } -> hash
@@ -24,6 +26,7 @@ class Hash
24
26
  alias_method :hash_find_all, :hash_select
25
27
  alias_method :delete_unless, :hash_select
26
28
  end
29
+ end
27
30
 
28
31
  # _____ _
29
32
  # |_ _|__ ___| |_
@@ -34,7 +37,7 @@ end
34
37
  =begin test
35
38
  require 'test/unit'
36
39
 
37
- class TheTest < Test::Unit::TestCase
40
+ class HashSelectTest < Test::Unit::TestCase
38
41
  def test_1
39
42
  hash_copy = hash = {:a => 1, :b => 2}
40
43
  assert_equal hash.reject {|k,v| k != :b},
@@ -0,0 +1,48 @@
1
+ duplicates = {}
2
+
3
+ people_by_name = {}
4
+ @people.each do |person|
5
+ people_by_name[person.name] ||= []
6
+ people_by_name[person.name] << person
7
+ end
8
+ people_by_name.reject! {|name, people| people.size < 2}
9
+ # Merge elements of this hash back into duplicates, unless it already contains a value (a duplicate) for that value (even if it's for a different key). We don't want to have duplicate duplicates!
10
+ #duplicates.merge_if(people_by_name) {|k, v| !duplicates.values.include?(v) }
11
+ require 'ruby-debug'; debugger
12
+ people_by_name.each {|k, v| duplicates[k] = v unless duplicates.values.include?(v) }
13
+
14
+ people_by_wwu_id = {}
15
+ @people.each do |person|
16
+ people_by_wwu_id[person.wwu_id] ||= []
17
+ people_by_wwu_id[person.wwu_id] << person
18
+ end
19
+ people_by_wwu_id.reject! {|wwu_id, people| people.size < 2}
20
+ people_by_name.each {|k, v|
21
+ duplicates[k] = v unless duplicates.values.include?(v)
22
+ }
23
+
24
+ people_by_email = {}
25
+ @people.each do |person|
26
+ people_by_wwu_id[person.email_address] ||= []
27
+ people_by_wwu_id[person.email_address] << person
28
+ end
29
+ people_by_email.reject! {|wwu_id, people| people.size < 2}
30
+ people_by_name.each {|k, v|
31
+ duplicates[k] = v unless duplicates.values.include?(v)
32
+ }
33
+
34
+ puts "These people have duplicates:"
35
+ duplicates.each do |key, people|
36
+ next if key.blank?
37
+ puts
38
+ puts key
39
+ people.each do |person|
40
+ puts "#{person.id} ('#{person.first_name}' '#{person.last_name}')".ljust(27) + ' ' +
41
+ (person.username || '').ljust(17) + ' ' +
42
+ (person.wwu_id || '').ljust(9) + ' ' +
43
+ person.created_at.strftime("%Y-%m-%d %H:%M") + ' ' +
44
+ (person.last_successful_login_at && person.last_successful_login_at.strftime("%Y-%m-%d %H:%M")).to_s.ljust(16) + ' ' +
45
+ 'Profiles: ' + person.profiles.map {|p| "#{p.volume.name} (#{p.user_type.name}, #{p.photos.size} photos)"}.join(', ')
46
+ end
47
+ end
48
+
@@ -21,11 +21,12 @@ require 'quality_extensions/module/attribute_accessors'
21
21
  # alternative is dirt simple, and it still works.
22
22
  module ExamplePrinter
23
23
  # Prints the given statement (+code+ -- a string) before evaluating it.
24
- # Same as xmp only it doesn't print the return value.
24
+ # Same as xmp only it doesn't print the return value. Is it instead of xmp when the return value isn't interesting or might even be distracting to the reader.
25
25
  #
26
26
  # o = nil
27
- # xmp 'o = C.new', binding
28
- # # => o = C.new
27
+ # put_statement 'o = C.new', binding
28
+ # # Outputs:
29
+ # # o = C.new
29
30
  def put_statement(code, binding = nil, file = __FILE__, line = __LINE__)
30
31
 
31
32
  # We'd like to be able to just use the binding of the caller without passing it in, but unfortunately I don't know how (yet)...
@@ -46,6 +47,12 @@ module ExamplePrinter
46
47
  # Pretty much compatible with irb/xmp. But you have currently have to pass
47
48
  # in the binding manually if you have any local variables/methods that xmp
48
49
  # should have access to.
50
+ #
51
+ # o = nil
52
+ # xmp '3 + x', binding
53
+ # # Outputs:
54
+ # # 3 + x
55
+ # # => 4
49
56
  def xmp(code, binding = nil, options = {})
50
57
  result = put_statement(code, binding)
51
58
  puts "=> #{result}"
@@ -38,8 +38,14 @@ module Kernel
38
38
  else
39
39
  raise ArgumentError.new("Expected a String or a FileList")
40
40
  end
41
- files = files.exclude(*exclusions) if (exclusions = options.delete(:exclude))
42
- files = files.exclude(*exclusions.map {|a| File.exact_match_regexp(a) }) if (exclusions = options.delete(:exclude_files))
41
+ if (exclusions = options.delete(:exclude))
42
+ exclusions = [exclusions] if exclusions.is_a? String
43
+ files = files.exclude(*exclusions)
44
+ end
45
+ if (exclusions = options.delete(:exclude_files))
46
+ exclusions = [exclusions] if exclusions.is_a? String
47
+ files = files.exclude(*exclusions.map {|a| File.exact_match_regexp(a) })
48
+ end
43
49
 
44
50
  files.each do |filename|
45
51
  # puts "requiring #{filename}" if filename =~ /test/
@@ -106,12 +112,13 @@ class TheTest < Test::Unit::TestCase
106
112
  assert_equal ['moo.rb'], $loaded
107
113
 
108
114
  # But, we can still trick it!
109
- $LOAD_PATH << @base_dir
110
- require "moo"
111
- assert_equal ['moo.rb', 'moo.rb'], $loaded
112
-
113
- load "moo.rb"
114
- assert_equal ['moo.rb', 'moo.rb', 'moo.rb'], $loaded
115
+ # Update: Apparently, in Ruby 1.9.1, this no longer works. moo.rb will only be required once.
116
+ # $LOAD_PATH << @base_dir
117
+ # require "moo"
118
+ # assert_equal ['moo.rb', 'moo.rb'], $loaded
119
+ #
120
+ # load "moo.rb"
121
+ # assert_equal ['moo.rb', 'moo.rb', 'moo.rb'], $loaded
115
122
  end
116
123
 
117
124
  def test_deep_subdir
@@ -172,6 +179,15 @@ class TheTest < Test::Unit::TestCase
172
179
  assert_equal ['yes.rb'], $loaded
173
180
  end
174
181
 
182
+ def test_exclude_filename_string
183
+ create_ruby_file 'yes2.rb'
184
+ create_ruby_file 'all2.rb'
185
+
186
+ require_all File.dirname(@base_dir), :exclude_files => 'all2.rb'
187
+
188
+ assert_equal ['yes2.rb'], $loaded
189
+ end
190
+
175
191
  #-------------------------------------------------------------------------------------------------------------------------------
176
192
  # Helpers
177
193
 
@@ -0,0 +1,108 @@
1
+ module Kernel
2
+
3
+ # Sleeps for integer +n+ number of seconds, by default counting down from +n+ (inclusive) to 0, with a +step+ size of -1, printing the value of the counter at each step (3, 2, 1, 0 (output 4 times) if +n+ is 3), each time separated by a ', '.
4
+ #
5
+ # In effect, it is a simple on-screen countdown (or count-up) timer.
6
+ #
7
+ # To change the step size, supply a value for +step+ other than -1 (the default). It will sleep for +step.abs+ seconds between each iteration, and at each iteration will either yield to the supplied block or (the default) output the current value of the counter).
8
+ #
9
+ # The value of +step+ also determines in which *direction* to count:
10
+ # If +step+ is negative (the default), it counts *down* from +n+ down to 0 (inclusive).
11
+ # If +step+ is positive, it counts *up* from 0 up to +n+ (inclusive).
12
+ #
13
+ # +step+ does not need to be an integer value.
14
+ #
15
+ # If +n+ is not evenly divisible by +step+ (that is, if step * floor( / ? ) > n), the final step size will be shorter to ensure that the total amount slept is +n+ seconds. More precisely, the amount of time it sleeps before the final iteration (during which it won't sleepat all) will
16
+ #
17
+ # If a block is provided, all of the default output is overridden, and the block will be yielded with the value of the counter i once every second instead of the default behavior, allowing you to customize what gets output, if anything, or what else happens, every +n.abs+ seconds.
18
+ #
19
+ # Note that it produces output (or executes your block, if supplied) n+1 times, *not* n times. This allows you to output (or not) both when the timer is first started *and* when it finishes. But because it sleeps for 1 second after the first n iterations only and *not* after the last, the total delay is still only n seconds.
20
+ #
21
+ # Examples:
22
+ #
23
+ # sleep_loudly(3)
24
+ # 3<sleep 1>2, <sleep 1>1, <sleep 1>0
25
+ #
26
+ # sleep_loudly(3) {|i| puts(i == 0 ? 'Done' : i)}
27
+ # 3<sleep 1>
28
+ # 2<sleep 1>
29
+ # 1<sleep 1>
30
+ # Done
31
+ #
32
+ # sleep_loudly(10*60, :up, 60) {|i| print i*60, ", "} # sleep for 10 minutes, outputting after every 60 seconds
33
+ # 0<sleep 60>2, <sleep 60>2, <sleep 60>3,
34
+ #
35
+ # sleep_loudly(3, :up) {|i| print i}
36
+ # 0<sleep 1>1<sleep 1>2<sleep 1>3
37
+ #
38
+ # sleep_loudly(3, :up) {|i| print i+1 unless i==3}
39
+ # 1<sleep 1>2<sleep 1>3<sleep 1>
40
+ #
41
+ def sleep_loudly(n, step = -1, options = {}, &block)
42
+ debug = options[:debug] == true ? 1 : 0
43
+ #debug = 1
44
+
45
+ old_sync, STDOUT.sync = STDOUT.sync, true
46
+ if step < 0
47
+ starti, endi = n, 0
48
+ elsif step > 0
49
+ starti, endi = 0, n
50
+ else
51
+ raise ArgumentError, "step must be positive or negative, not 0"
52
+ end
53
+
54
+ puts "Counting from #{starti} to #{endi} in increments of #{step} (total time should be n=#{n})" if debug
55
+
56
+ i = starti
57
+ final = false
58
+ loop do
59
+ print 'final' if final
60
+ if block_given?
61
+ yield *[i, final][0..block.arity-1]
62
+ else
63
+ print "#{i}"
64
+ end
65
+
66
+ break if final
67
+
68
+ remaining = (i - endi).abs
69
+
70
+ # if n was a multiple of step, remaining will eventually be 0, telling us that there is one final iteration to go
71
+ # if n was not a multiple of step, use a different, smaller step as the final step; and we know that there is one final iteration to go
72
+ if remaining < step.abs
73
+ s = (step < 0 ? i-endi : endi-i)
74
+ print " (using smaller final step #{s}) " if debug
75
+ final = true # the next iteration is the final one
76
+ else
77
+ s = step
78
+ end
79
+ i += s
80
+ print " (+#{s}=#{i}) " if debug
81
+
82
+ print ", " unless block_given?
83
+ print " (sleeping for #{s.abs}) " if debug
84
+ sleep s.abs
85
+ end
86
+
87
+ print "\n" unless block_given?
88
+ STDOUT.sync = old_sync
89
+ end
90
+ end
91
+
92
+ =begin tests
93
+ # To do: convert to use test framework
94
+ debug = 1
95
+ require 'benchmark'
96
+ def benchmark(&block)
97
+ puts(Benchmark.measure { yield })
98
+ end
99
+ benchmark { sleep_loudly(2, 1, :debug => true) }
100
+ #benchmark { sleep_loudly(3, -1) }
101
+ #benchmark { sleep_loudly(3.2) }
102
+ #benchmark { sleep_loudly(3) {|i| print i}; puts }
103
+ #benchmark { sleep_loudly(3) {|i| print i+1 unless i==3} }
104
+ #benchmark { sleep_loudly(3) {|i| puts(i == 0 ? 'Done' : i)} }
105
+ benchmark { sleep_loudly(n=4, 1.5) {|i| print i; print ", "}; puts }
106
+ benchmark { sleep_loudly(n=5, 2) {|i, final| break if final; print i/2; print ", "}; puts }
107
+ #benchmark { sleep_loudly(n=5, 2) }
108
+ =end
@@ -0,0 +1,22 @@
1
+ # Source: http://svn.idaemons.org/repos/inplace/trunk/inplace.rb
2
+
3
+ $uninterruptible = false
4
+
5
+ [:SIGINT, :SIGQUIT, :SIGTERM].each { |sig|
6
+ trap(sig) {
7
+ unless $uninterruptible
8
+ STDERR.puts "Interrupted."
9
+ exit 130
10
+ end
11
+ }
12
+ }
13
+
14
+ def uninterruptible
15
+ orig = $uninterruptible
16
+ $uninterruptible = true
17
+
18
+ yield
19
+ ensure
20
+ $uninterruptible = orig
21
+ end
22
+
@@ -0,0 +1,68 @@
1
+ #--
2
+ # Author:: Tyler Rick
3
+ # Copyright:: Copyright (c) 2009, Tyler Rick
4
+ # License:: Ruby License
5
+ # Submit to Facets?:: Yes
6
+ # Developer notes::
7
+ # History::
8
+ #++
9
+
10
+ require 'matrix'
11
+
12
+ class Matrix
13
+ #
14
+ # Changes element (+i+,+j+) of the matrix. (That is: row +i+, column +j+.)
15
+ #
16
+ def []=(i, j, new)
17
+ @rows[i][j] = new
18
+ end
19
+ end
20
+
21
+ class Vector
22
+ #
23
+ # Changes element number +i+ (starting at zero) of the vector.
24
+ #
25
+ def []=(i, new)
26
+ @elements[i] = new
27
+ end
28
+ end
29
+
30
+ # _____ _
31
+ # |_ _|__ ___| |_
32
+ # | |/ _ \/ __| __|
33
+ # | | __/\__ \ |_
34
+ # |_|\___||___/\__|
35
+ #
36
+ =begin test
37
+ require 'spec'
38
+
39
+ describe 'Matrix' do
40
+ it '#[]=' do
41
+ m = Matrix[['a', 'b'], ['c', 'd']]
42
+ m[0, 0] = 'new'
43
+ m.should == Matrix[['new', 'b'], ['c', 'd']]
44
+ end
45
+ end
46
+
47
+ describe 'Vector' do
48
+ it '#[]=' do
49
+ v = Vector[1, 2]
50
+ v[0] = 10
51
+ v.should == Vector[10, 2]
52
+ end
53
+
54
+ it 'Chanhing vector returned by Matrix#column by using Vector#[]= will not change the values in the Matrix' do
55
+ m = Matrix[['a', 'b'], ['c', 'd']]
56
+
57
+ v = m.column(0)
58
+ v[1] = 'new'
59
+ v.should == Vector['a', 'new']
60
+ m.column(0).should == Vector['a', 'c'] # []= only changes the vector
61
+
62
+ m.column(0)[1].replace 'new' # changes the string object itself, which both vector and matrix share
63
+ m.column(0).should == Vector['a', 'new']
64
+ m.column(0).should == Vector['a', 'new']
65
+ end
66
+ end
67
+ =end
68
+
@@ -0,0 +1,137 @@
1
+ #--
2
+ # Author:: Tyler Rick
3
+ # Copyright:: Copyright (c) 2009, Tyler Rick
4
+ # License:: Ruby License
5
+ # Submit to Facets?:: Yes
6
+ # Developer notes::
7
+ # User notes:: Only changes done via []= are currenly propagated back to the parent matrix!
8
+ # History::
9
+ #++
10
+
11
+ require 'matrix'
12
+ require File.dirname(__FILE__) + "/indexable"
13
+
14
+ # Idea: could also hide this functionality in a module which is then included as needed
15
+ #class Matrix
16
+ # module VectorsLinkedToParentMatrix
17
+ # end
18
+ #end
19
+
20
+ #---------------------------------------------------------------------------------------------------
21
+ class Matrix
22
+ MatrixDetails = Struct.new(:matrix, :i)
23
+
24
+ #
25
+ # Returns row vector number +i+ of the matrix as a Vector (starting at 0 like
26
+ # an array). When a block is given, the elements of that vector are iterated.
27
+ #
28
+ def row(i) # :yield: e
29
+ if block_given?
30
+ for e in @rows[i]
31
+ yield e
32
+ end
33
+ else
34
+ # Because an array of rows happens to be the native internal format of a matrix, the only thing changed was passing copy = false instead of copy = true. Then the rows are passed by reference instead of dup'd and any changes made to them will automatically be made in the matrix as well.
35
+ Vector.elements(@rows[i], false)
36
+ end
37
+ end
38
+
39
+ #
40
+ # Returns column vector number +j+ of the matrix as a Vector (starting at 0
41
+ # like an array). When a block is given, the elements of that vector are
42
+ # iterated.
43
+ #
44
+ def column(j) # :yield: e
45
+ if block_given?
46
+ 0.upto(row_size - 1) do
47
+ |i|
48
+ yield @rows[i][j]
49
+ end
50
+ else
51
+ col = (0 .. row_size - 1).collect {
52
+ |i|
53
+ @rows[i][j]
54
+ }
55
+ # With column vectors, it's a bit trickier to link changes so they propagate to the matrix. The matrix doesn't natively store an array of column arrays. The column array constructed here is already a copy. So we pass the matrix by reference and the column number so that we can later use Matrix#[]= to propagate changes to the vector back to the matrix.
56
+ Vector.elements(col, false, MatrixDetails.new(self, j))
57
+ end
58
+ end
59
+ end
60
+
61
+ class Vector
62
+ #
63
+ # Creates a vector from an Array. The optional second argument specifies
64
+ # whether the array itself or a copy is used internally.
65
+ #
66
+ def Vector.elements(array, copy = true, matrix_details = nil)
67
+ new(:init_elements, array, copy, matrix_details)
68
+ end
69
+
70
+ #
71
+ # For internal use.
72
+ #
73
+ def initialize(method, array, copy, matrix_details = nil)
74
+ self.send(method, array, copy)
75
+ @matrix_details = matrix_details
76
+ end
77
+
78
+ #
79
+ # Updates element number +i+ (starting at zero) of the vector.
80
+ #
81
+ # If this vector is linked with (a row or column of) a matrix, it changes the corresponding element of that matrix too.
82
+ #
83
+ def []=(i, new)
84
+ @elements[i] = new
85
+
86
+ # Update linked matrix too
87
+ if @matrix_details.respond_to? :matrix
88
+ #puts "@matrix_details.matrix[#{i}, #{@matrix_details.i}] = #{new.inspect}"
89
+ @matrix_details.matrix[i, @matrix_details.i] = new
90
+ end
91
+ end
92
+ end
93
+
94
+ # _____ _
95
+ # |_ _|__ ___| |_
96
+ # | |/ _ \/ __| __|
97
+ # | | __/\__ \ |_
98
+ # |_|\___||___/\__|
99
+ #
100
+ =begin test
101
+ require 'spec'
102
+
103
+ describe 'Matrix' do
104
+ it '#[]=' do
105
+ m = Matrix[['a', 'b'], ['c', 'd']]
106
+ m[0, 0] = 'new'
107
+ m.should == Matrix[['new', 'b'], ['c', 'd']]
108
+ end
109
+ end
110
+
111
+ describe 'Changing vector returned by Matrix#column/row by using Vector#[]=' do
112
+ it '#[]=' do
113
+ v = Vector[1, 2]
114
+ v[0] = 10
115
+ v.should == Vector[10, 2]
116
+ end
117
+
118
+ it '(column) *will* change the values in the linked Matrix' do
119
+ m = Matrix[['a', 'b'], ['c', 'd']]
120
+
121
+ v = m.column(0)
122
+ v[0] = 'new'
123
+ v.should == Vector['new', 'c']
124
+ m.column(0).should == Vector['new', 'c']
125
+ end
126
+
127
+ it '(row) *will* change the values in the linked Matrix' do
128
+ m = Matrix[['a', 'b'], ['c', 'd']]
129
+
130
+ v = m.row(0)
131
+ v[0] = 'new'
132
+ v.should == Vector['new', 'b']
133
+ m.row(0).should == Vector['new', 'b']
134
+ end
135
+ end
136
+ =end
137
+
@@ -14,6 +14,8 @@ class Object
14
14
  (
15
15
  methods(include_super) \
16
16
  - instance_methods
17
+ #- Object.instance_methods ?
18
+ #- Module.methods
17
19
  ).
18
20
  sort
19
21
  end
@@ -0,0 +1,12 @@
1
+ class Object
2
+ def nonblank?
3
+ !blank?
4
+ end
5
+ end
6
+
7
+ class Object
8
+ def nonnil?
9
+ !nil?
10
+ end
11
+ end
12
+