facets 2.8.2 → 2.8.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. data/AUTHORS +13 -11
  2. data/HISTORY.rdoc +58 -0
  3. data/lib/core/facets/array/recursive.rb +91 -0
  4. data/lib/core/facets/array/recursively.rb +2 -2
  5. data/lib/core/facets/array/traverse.rb +23 -6
  6. data/lib/core/facets/enumerable/collisions.rb +1 -0
  7. data/lib/core/facets/enumerable/commonality.rb +4 -2
  8. data/lib/core/facets/enumerable/graph.rb +37 -1
  9. data/lib/core/facets/enumerable/mash.rb +1 -39
  10. data/lib/core/facets/enumerable/recursive.rb +75 -0
  11. data/lib/core/facets/enumerable/visit.rb +30 -0
  12. data/lib/core/facets/file/ext.rb +36 -0
  13. data/lib/core/facets/hash/graph.rb +18 -0
  14. data/lib/core/facets/hash/mash.rb +1 -18
  15. data/lib/core/facets/hash/recursive.rb +180 -0
  16. data/lib/core/facets/hash/recursive_merge.rb +6 -0
  17. data/lib/core/facets/hash/recursively.rb +2 -2
  18. data/lib/core/facets/hash/to_module.rb +26 -0
  19. data/lib/core/facets/hash/to_proc.rb +2 -2
  20. data/lib/core/facets/hash/traverse.rb +19 -13
  21. data/lib/core/facets/kernel/assign.rb +63 -0
  22. data/lib/core/facets/kernel/assign_from.rb +45 -0
  23. data/lib/core/facets/kernel/dup.rb +63 -0
  24. data/lib/core/facets/kernel/instance.rb +156 -0
  25. data/lib/core/facets/kernel/instance_assign.rb +1 -22
  26. data/lib/core/facets/kernel/meta_def.rb +4 -0
  27. data/lib/core/facets/kernel/populate.rb +1 -74
  28. data/lib/core/facets/kernel/set_from.rb +2 -0
  29. data/lib/core/facets/kernel/try_dup.rb +1 -0
  30. data/lib/core/facets/module/set.rb +36 -0
  31. data/lib/core/facets/objectspace/reflect.rb +45 -0
  32. data/lib/core/facets/struct/attributes.rb +6 -2
  33. data/lib/core/facets/symbol/op_div.rb +19 -0
  34. data/lib/core/facets/to_hash.rb +12 -0
  35. data/lib/more/facets/casting_hash.rb +172 -0
  36. data/lib/more/facets/pathname.rb +36 -0
  37. data/lib/more/facets/prepend.rb +57 -0
  38. data/lib/more/facets/random.rb +19 -3
  39. data/lib/more/facets/roman.rb +46 -153
  40. data/lib/more/facets/stash.rb +148 -33
  41. data/meta/released +1 -1
  42. data/meta/version +1 -1
  43. data/test/core/array/test_recursive.rb +18 -0
  44. data/test/core/enumerable/test_recursive.rb +18 -0
  45. data/test/core/file/test_ext.rb +31 -0
  46. data/test/core/hash/test_recursive.rb +23 -0
  47. data/test/core/hash/test_to_module.rb +21 -0
  48. data/test/core/kernel/test_assign.rb +57 -0
  49. data/test/core/kernel/test_assign_from.rb +20 -0
  50. data/test/more/test_prepend.rb +28 -0
  51. data/test/more/test_random.rb +40 -4
  52. metadata +39 -10
  53. data/lib/core/facets/kernel/instance_variables.rb +0 -97
  54. data/lib/more/facets/instance_eval.rb +0 -50
  55. data/lib/more/facets/ioredirect.rb +0 -77
  56. data/lib/more/facets/plugin_manager.rb +0 -50
  57. data/test/core/kernel/test_populate.rb +0 -46
@@ -1,11 +1,15 @@
1
1
  class Struct
2
2
 
3
- # Returns a hash containing the names and values for all instance variables in the Struct.
3
+ # Returns a hash containing the names and values
4
+ # for all instance settings in the Struct.
5
+ #
6
+ # This will eventually be deprecated in favor of #to_h.
7
+
4
8
  def attributes
5
9
  h = {}
6
10
  each_pair { |k,v| h[k] = v }
7
11
  h
8
12
  end
9
13
 
10
- end # class Struct
14
+ end
11
15
 
@@ -0,0 +1,19 @@
1
+ class Symbol
2
+
3
+ # Join with _path_ as a file path.
4
+ #
5
+ # :merb / "core_ext" #=> "merb/core_ext"
6
+ # :merb / :core_ext / :string #=> "merb/core_ext/string"
7
+ #
8
+ # @param [#to_s] path The path component(s) to append.
9
+ #
10
+ # @return [String] The receiver (as path string), concatenated with _path_.
11
+ #
12
+ # @api public
13
+
14
+ def /(path)
15
+ File.join(to_s, path.to_s)
16
+ end
17
+
18
+ end
19
+
@@ -318,3 +318,15 @@ class Enumerator
318
318
 
319
319
  end
320
320
 
321
+ class Struct
322
+
323
+ # Returns a hash containing the names and values
324
+ # for all instance settings in the Struct.
325
+ def to_h
326
+ h = {}
327
+ each_pair{ |k,v| h[k] = v }
328
+ h
329
+ end
330
+
331
+ end
332
+
@@ -0,0 +1,172 @@
1
+ # CastingHash is just like Hash, except that all keys and values
2
+ # are passed through casting procedures.
3
+ #--
4
+ # TODO: Handle default_proc.
5
+ #++
6
+ class CastingHash < Hash
7
+
8
+ # Default key conversion procedure.
9
+ KEY_PROC = lambda{ |x| x } #.to_s }
10
+
11
+ # Default value conversion procedure.
12
+ VAL_PROC = lambda{ |x| x }
13
+
14
+ #
15
+ def self.[](hash)
16
+ s = new
17
+ hash.each{ |k,v| s[k] = v }
18
+ s
19
+ end
20
+
21
+ #
22
+ def initialize(hash, value_cast=nil, &key_cast)
23
+ @key_proc = key_cast || KEY_PROC
24
+ @value_proc = value_cast.to_proc || VAL_PROC
25
+ hash.each{ |k,v| self[k] = v }
26
+ end
27
+
28
+ #
29
+ def key_proc
30
+ @key_proc
31
+ end
32
+
33
+ #
34
+ def key_proc=(proc)
35
+ @key_proc = proc.to_proc
36
+ end
37
+
38
+ #
39
+ def value_proc
40
+ @value_proc
41
+ end
42
+
43
+ #
44
+ def value_proc=(proc)
45
+ @value_proc = proc.to_proc
46
+ end
47
+
48
+ #
49
+ def [](k)
50
+ super(key_proc[k])
51
+ end
52
+
53
+ #
54
+ def []=(k,v)
55
+ super(key_proc[k], value_proc[v])
56
+ end
57
+
58
+ #
59
+ def <<(other)
60
+ case other
61
+ when Hash
62
+ super(cast(other))
63
+ when Array
64
+ self[other[0]] = other[1]
65
+ else
66
+ raise ArgumentError
67
+ end
68
+ end
69
+
70
+ def fetch(k)
71
+ super(key_proc[k])
72
+ end
73
+
74
+ #
75
+ def store(k, v)
76
+ super(key_proc[k], value_proc[v])
77
+ end
78
+
79
+ #
80
+ def key?(k)
81
+ super(key_proc[k])
82
+ end
83
+
84
+ #
85
+ def has_key?(k)
86
+ super(key_proc[k])
87
+ end
88
+
89
+ # Synonym for Hash#rekey, but modifies the receiver in place (and returns it).
90
+ #
91
+ # foo = { :name=>'Gavin', :wife=>:Lisa }.to_stash
92
+ # foo.rekey!{ |k| k.upcase } #=> { "NAME"=>"Gavin", "WIFE"=>:Lisa }
93
+ # foo.inspect #=> { "NAME"=>"Gavin", "WIFE"=>:Lisa }
94
+ #
95
+ def rekey!(*args, &block)
96
+ # for backward comptability (DEPRECATE?).
97
+ block = args.pop.to_sym.to_proc if args.size == 1
98
+ if args.empty?
99
+ block = lambda{|k| k} unless block
100
+ keys.each do |k|
101
+ nk = block[k]
102
+ self[nk] = delete(k) #if nk
103
+ end
104
+ else
105
+ raise ArgumentError, "3 for 2" if block
106
+ to, from = *args
107
+ self[to] = delete(from) if has_key?(from)
108
+ end
109
+ self
110
+ end
111
+
112
+ #
113
+ def rekey(*args, &block)
114
+ dup.rekey!(*args, &block)
115
+ end
116
+
117
+ #
118
+ def delete(k)
119
+ super(key_proc[k])
120
+ end
121
+
122
+ #
123
+ def update(other)
124
+ super(cast(other))
125
+ end
126
+
127
+ # Same as #update.
128
+ def merge!(other)
129
+ super(cast(other))
130
+ end
131
+
132
+ #
133
+ def replace(other)
134
+ super(cast(other))
135
+ end
136
+
137
+ #
138
+ def values_at(*keys)
139
+ super(keys.map(&key_proc))
140
+ end
141
+
142
+ #
143
+ def to_hash
144
+ h = {}; each{ |k,v| h[k] = v }; h
145
+ end
146
+
147
+ #
148
+ alias_method :to_h, :to_hash
149
+
150
+ private
151
+
152
+ #
153
+ def cast(hash)
154
+ h
155
+ hash.each do |k,v|
156
+ h[key_proc[k]] = value_proc[v]
157
+ end
158
+ h
159
+ end
160
+
161
+ end
162
+
163
+
164
+ class Hash
165
+
166
+ # Convert a Hash to a Stash object.
167
+ def to_casting_hash(value_cast=nil, &key_cast)
168
+ CastingHash.new(self, value_cast, &key_cast)
169
+ end
170
+
171
+ end
172
+
@@ -25,6 +25,10 @@ require 'facets/file/rootname'
25
25
 
26
26
  class Pathname
27
27
 
28
+ # Alias #to_s to #to_str when #to_str is not defined.
29
+ #
30
+ alias_method(:to_str, :to_s) unless method_defined?(:to_str)
31
+
28
32
  # Alternate to Pathname#new.
29
33
  #
30
34
  # Pathname['/usr/share']
@@ -148,6 +152,38 @@ class Pathname
148
152
  ::FileUtils.outofdate?(to_s, sources.flatten)
149
153
  end
150
154
 
155
+ # Recursively visit a directory located by its path, yielding each resource
156
+ # as its full matching pathname object. If called on a file, yield the file.
157
+ #
158
+ # call-seq:
159
+ # visit => yield each file
160
+ # visit(all: true) => yield visited directories as well
161
+ # visit(hidden: true) => yield hidden files and directories as well
162
+ #
163
+ # Example use case:
164
+ #
165
+ # # get rid of any file but *.haml within app/**/*
166
+ # Pathname.new("app").visit do |f|
167
+ # FileUtils.rm_f(f) unless f.to_s =~ /\.haml$/
168
+ # puts "!!! deleting #{f}"
169
+ # end
170
+ #
171
+ # CREDIT: Jean-Denis Vauguet
172
+ def visit(options = {:all => false, :hidden => false})
173
+ if self.directory?
174
+ children.each do |entry|
175
+ next if entry.basename.to_s[0] == "." && !options[:hidden]
176
+ yield(entry) unless entry.directory? && !options[:all]
177
+ #entry.visit(:all => options[:all]) { |sub_entry| yield sub_entry } if entry.directory?
178
+ entry.visit(:all => options[:all], :hidden => options[:hidden]) do |sub_entry|
179
+ yield(sub_entry)
180
+ end if entry.directory?
181
+ end
182
+ else
183
+ yield self
184
+ end
185
+ end
186
+
151
187
  # # Already included in 1.8.4+ version of Ruby (except for inclusion flag)
152
188
  # if not instance_methods.include?(:ascend)
153
189
  #
@@ -0,0 +1,57 @@
1
+ # :title: Prepend
2
+ # :copyright: Copyright (c) 2005 Thomas Sawyer
3
+ # :license: Ruby License
4
+ # :description: Prepend a module to another module, or to a class.
5
+
6
+ # = Prepend
7
+ #
8
+ # This is a module prepend system, which provides an elegant
9
+ # way to prepend code to the class hierarchy rather then append
10
+ # it (a la #include).
11
+ #
12
+ # class C
13
+ # def f
14
+ # "f"
15
+ # end
16
+ # end
17
+ #
18
+ # module M
19
+ # def f
20
+ # '{' + super + '}'
21
+ # end
22
+ # end
23
+ #
24
+ # class C
25
+ # prepend M
26
+ # end
27
+ #
28
+ # c = C.new
29
+ # c.f #=> "{f}"
30
+ #
31
+ # This works by overriding Class#new so that all prepended modules
32
+ # extend new instances of the class upon instantiation.
33
+ #
34
+ # If needed the original #new method has been aliased as #init.
35
+
36
+ class Class
37
+
38
+ #
39
+ def prepend(*mods)
40
+ @prepend ||= []
41
+ @prepend.concat(mods)
42
+ @prepend
43
+ end
44
+
45
+ alias_method :init, :new
46
+
47
+ def new(*args, &blk)
48
+ o = allocate
49
+ prepend.each do |mod|
50
+ o.extend(mod)
51
+ end
52
+ o.__send__(:initialize, *args, &blk) #if private_method_defined?(:initialize)
53
+ o
54
+ end
55
+
56
+ end
57
+
@@ -53,7 +53,7 @@ require 'facets/string/shatter'
53
53
  module Random
54
54
 
55
55
  class << self
56
- # alias to Kernel method #rand.
56
+ # Alias for Kernel#rand.
57
57
  alias_method :number, :rand
58
58
  public :number
59
59
  end
@@ -79,6 +79,8 @@ module Random
79
79
  end
80
80
  end
81
81
 
82
+ #
83
+
82
84
  module Object
83
85
 
84
86
  # Random generator that returns true or false.
@@ -106,9 +108,23 @@ module Random
106
108
  # (1..4).at_rand #=> 2
107
109
  # (1..4).at_rand #=> 4
108
110
  #
111
+ # (1.5..2.5).at_rand #=> 2.06309842754533
112
+ # (1.5..2.5).at_rand #=> 1.74976944931541
113
+ #
114
+ # ('a'..'z').at_rand #=> 'q'
115
+ # ('a'..'z').at_rand #=> 'f'
116
+ #
117
+ # CREDIT: Lavir the Whiolet
118
+
109
119
  def at_rand
110
- array = to_a
111
- array.at(Random.number(array.size))
120
+ if first.respond_to?(:succ)
121
+ to_a.at_rand
122
+ elsif Numeric===first && Numeric===last
123
+ number = (last - first) * Random.number + first
124
+ (number == last && exclude_end?) ? first : number
125
+ else
126
+ nil
127
+ end
112
128
  end
113
129
 
114
130
  end
@@ -1,174 +1,67 @@
1
- # = TITLE:
2
- # Roman Numerals
3
- #
4
- # = SYNOPSIS:
5
- # Generates roman numerals from integers and vice-versa.
6
- #
7
- # = NOTES:
8
- # A response to Ruby Quiz of the Week #22 - Roman Numerals [ruby-talk:132925]
9
- #
10
- # = AUTHORS:
11
- # - Dave Burt <dave at burt.id.au>
12
- # - Trans
13
-
14
- module English #:nodoc:
15
-
16
- # Contains methods to convert integers to roman numeral strings and vice-versa.
17
-
18
- module RomanNumerals
19
-
20
- # The largest integer representable as a roman
21
- # numerable by this module.
22
-
23
- MAX = 3999
24
-
25
- # Stolen from O'Reilly's Perl Cookbook 6.23. Regular Expression Grabbag.
26
-
27
- REGEXP = /^M*(D?C{0,3}|C[DM])(L?X{0,3}|X[LC])(V?I{0,3}|I[VX])$/i
28
-
29
- #
30
-
31
- SYMBOLS = [ "M", "D", "C", "L", "X", "V", "I" ]
32
- NUMBERS = [ 1000, 500, 100, 50, 10, 5, 1 ]
33
-
34
-
35
- # Maps roman numeral digits to their integer values.
36
- # {
37
- # 'I' => 1,
38
- # 'V' => 5,
39
- # 'X' => 10,
40
- # 'L' => 50,
41
- # 'C' => 100,
42
- # 'D' => 500,
43
- # 'M' => 1000,
44
- # }
45
-
46
- TABLE = Hash[*SYMBOLS.zip(NUMBERS).flatten]
1
+ class Integer
47
2
 
48
3
  #
49
-
50
- PAIR_SYMBOLS = [ "CM", "CD", "XC", "XL", "IX", "IV", "I" ]
51
- PAIR_NUMBERS = [ 900, 400, 90, 40, 9, 4, 1 ]
52
-
53
- # {
54
- # 'CM' => 900,
55
- # 'CD' => 400,
56
- # 'XC' => 90,
57
- # 'XL' => 40,
58
- # 'IX' => 9,
59
- # 'IV' => 4
60
- # }
61
-
62
- PAIR_TABLE = Hash[*PAIR_SYMBOLS.zip(PAIR_NUMBERS).flatten]
4
+ ROMAN_MAX = 3999
63
5
 
64
6
  #
7
+ ROMAN_VALUES = [
8
+ ["M", 1000],
9
+ ["CM", 900],
10
+ ["D", 500],
11
+ ["CD", 400],
12
+ ["C", 100],
13
+ ["XC", 90],
14
+ ["L", 50],
15
+ ["XL", 40],
16
+ ["X", 10],
17
+ ["IX", 9],
18
+ ["V", 5],
19
+ ["IV", 4],
20
+ ["I", 1]
21
+ ]
65
22
 
66
- LOOKUP = TABLE.invert.merge(PAIR_TABLE.invert)
67
-
68
-
69
- class << self
70
-
71
- # Converts +integer+ to a roman numeral.
72
-
73
- def from_integer(integer)
74
- return nil if integer < 0 || integer > MAX
75
-
76
- r = integer # remainder
77
- y = '' # result
78
-
79
- NUMBERS.each do |n|
80
- while r >= n
81
- r -= n
82
- y += LOOKUP[n]
83
- end
84
- break if r <= 0
85
- end
86
-
87
- return y
88
- end
89
-
90
- alias_method :roman, :from_integer
91
-
92
- # Converts +roman_string+, a roman numeral, to an integer
93
-
94
- def to_integer(roman_string)
95
- return nil unless roman_string.is_roman_numeral?
96
-
97
- l = nil # last
98
- i = 0 # integer result
99
-
100
- c = roman_string.to_s.upcase.split(//).reverse
101
-
102
- c.each do |d|
103
- if v = TABLE[d]
104
- if l && l > v
105
- i -= v
106
- else
107
- i += v
108
- end
109
- l = v
110
- end
23
+ # Converts this integer to a roman numeral.
24
+ def roman
25
+ int = self
26
+ #return nil if integer > ROMAN_MAX
27
+ return "-#{(-int).roman}" if int < 0
28
+ return "" if int == 0
29
+ ROMAN_VALUES.each do |(i, v)|
30
+ return(i + (int-v).roman) if v <= int
111
31
  end
112
-
113
- return i
114
- end
115
-
116
- alias_method :arabic, :to_integer
117
-
118
- # Returns true iif +string+ is a roman numeral.
119
-
120
- def is_roman_numeral?(string)
121
- REGEXP =~ string
122
- end
123
-
124
32
  end
125
33
 
126
34
  end
127
35
 
128
- end # module English
129
-
130
36
 
131
- class Integer
132
-
133
- def roman
134
- English::RomanNumerals.roman(self) || ''
135
- end
136
-
137
- # Converts this integer to a roman numeral.
138
-
139
- def to_s_roman
140
- English::RomanNumerals.from_integer(self) || ''
141
- end
142
-
143
- end
37
+ class String
144
38
 
39
+ # Taken from O'Reilly's Perl Cookbook 6.23. Regular Expression Grabbag.
40
+ ROMAN = /^M*(D?C{0,3}|C[DM])(L?X{0,3}|X[LC])(V?I{0,3}|I[VX])$/i
145
41
 
146
- class String
42
+ #
43
+ ROMAN_VALUES = Integer::ROMAN_VALUES.inject({}){ |h,(r,a)| h[r] = a; h }
147
44
 
148
- # Considers string a roman numeral numeral,
45
+ # Considers string a Roman numeral numeral,
149
46
  # and converts it to the corresponding integer.
150
-
151
- def to_i_roman
152
- English::RomanNumerals.to_integer(self)
47
+ def roman
48
+ roman = self
49
+ raise unless roman?
50
+ last = roman[-1,1]
51
+ roman.reverse.split('').inject(0) do |result, c|
52
+ if ROMAN_VALUES[c] < ROMAN_VALUES[last]
53
+ result -= ROMAN_VALUES[c]
54
+ else
55
+ last = c
56
+ result += ROMAN_VALUES[c]
57
+ end
58
+ end
153
59
  end
154
60
 
155
- # Returns true iif the subject is a roman numeral.
156
-
157
- def is_roman_numeral?
158
- English::RomanNumerals.is_roman_numeral?(self)
61
+ # Returns true iif the subject is a valid Roman numeral.
62
+ def roman?
63
+ ROMAN =~ self
159
64
  end
160
65
 
161
66
  end
162
67
 
163
-
164
- # # Quiz solution: filter that swaps roman and arabic numbers
165
- # if __FILE__ == $0
166
- # ARGF.each do |line|
167
- # line.chomp!
168
- # if line.is_roman_numeral?
169
- # puts line.to_i_roman
170
- # else
171
- # puts line.to_i.to_s_roman
172
- # end
173
- # end
174
- # end