facets 2.7.0 → 2.8.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.
Files changed (130) hide show
  1. data/HISTORY.rdoc +135 -294
  2. data/MANIFEST +40 -91
  3. data/NOTES +1 -1
  4. data/README.rdoc +10 -8
  5. data/Rakefile +11 -34
  6. data/demo/{hook.rd → hook.rdoc} +2 -0
  7. data/demo/{scenario_require.rd → scenario_require.rdoc} +3 -0
  8. data/lib/core/facets-live.rb +7 -5
  9. data/lib/core/facets.rb +379 -359
  10. data/lib/core/facets/array/conjoin.rb +2 -2
  11. data/lib/core/facets/array/pad.rb +1 -1
  12. data/lib/core/facets/array/recursively.rb +2 -2
  13. data/lib/core/facets/array/splice.rb +1 -1
  14. data/lib/core/facets/binding/caller.rb +2 -4
  15. data/lib/core/facets/comparable/comparable.rb +2 -2
  16. data/lib/core/facets/dir/ascend.rb +3 -0
  17. data/lib/core/facets/dir/recurse.rb +4 -0
  18. data/lib/core/facets/duplicable.rb +6 -8
  19. data/lib/core/facets/enumerable/count.rb +22 -13
  20. data/lib/core/facets/enumerable/map_detect.rb +28 -0
  21. data/lib/core/facets/enumerable/mash.rb +13 -5
  22. data/lib/core/facets/enumerable/per.rb +3 -1
  23. data/lib/core/facets/hash/count.rb +14 -0
  24. data/lib/core/facets/hash/data.rb +14 -0
  25. data/lib/core/facets/kernel/__method__.rb +1 -1
  26. data/lib/core/facets/kernel/d.rb +9 -8
  27. data/lib/core/facets/kernel/eigenclass.rb +20 -0
  28. data/lib/core/facets/kernel/extend.rb +10 -0
  29. data/lib/core/facets/kernel/instance_class.rb +1 -0
  30. data/lib/core/facets/kernel/instance_variables.rb +6 -6
  31. data/lib/core/facets/kernel/meta_alias.rb +18 -0
  32. data/lib/core/facets/kernel/meta_class.rb +17 -0
  33. data/lib/core/facets/kernel/meta_def.rb +18 -0
  34. data/lib/core/facets/kernel/meta_eval.rb +18 -0
  35. data/lib/core/facets/kernel/object_hexid.rb +21 -6
  36. data/lib/core/facets/kernel/object_state.rb +4 -2
  37. data/lib/core/facets/kernel/populate.rb +3 -1
  38. data/lib/core/facets/kernel/with.rb +1 -1
  39. data/lib/core/facets/metaid.rb +6 -93
  40. data/lib/core/facets/module/class_def.rb +2 -0
  41. data/lib/core/facets/module/extend.rb +10 -11
  42. data/lib/core/facets/module/is.rb +5 -5
  43. data/lib/core/facets/module/module_def.rb +31 -0
  44. data/lib/core/facets/string/camelcase.rb +14 -12
  45. data/lib/core/facets/string/cleanlines.rb +35 -0
  46. data/lib/core/facets/string/edit_distance.rb +62 -0
  47. data/lib/core/facets/string/indent.rb +86 -4
  48. data/lib/core/facets/string/index_all.rb +24 -0
  49. data/lib/core/facets/string/lines.rb +3 -6
  50. data/lib/core/facets/string/margin.rb +2 -1
  51. data/lib/core/facets/string/newlines.rb +35 -0
  52. data/lib/core/facets/string/op_div.rb +14 -0
  53. data/lib/core/facets/string/range.rb +2 -22
  54. data/lib/core/facets/string/range_all.rb +1 -0
  55. data/lib/core/facets/string/range_of_line.rb +1 -0
  56. data/lib/core/facets/string/similarity.rb +92 -0
  57. data/lib/core/facets/string/start_with.rb +6 -6
  58. data/lib/core/facets/string/titlecase.rb +1 -1
  59. data/lib/more/facets/basicobject.rb +16 -15
  60. data/lib/more/facets/blankslate.rb +8 -0
  61. data/lib/more/facets/class_extend.rb +126 -1
  62. data/lib/more/facets/continuation.rb +53 -54
  63. data/lib/more/facets/dictionary.rb +9 -63
  64. data/lib/more/facets/erb.rb +63 -0
  65. data/lib/more/facets/filelist.rb +5 -5
  66. data/lib/more/facets/hashbuilder.rb +101 -0
  67. data/lib/more/facets/inheritor.rb +36 -45
  68. data/lib/more/facets/ini.rb +267 -0
  69. data/lib/more/facets/instance_eval.rb +4 -4
  70. data/lib/more/facets/ioredirect.rb +7 -60
  71. data/lib/more/facets/linkedlist.rb +195 -0
  72. data/lib/more/facets/matcher.rb +140 -0
  73. data/lib/more/facets/memoizer.rb +64 -0
  74. data/lib/more/facets/methodspace.rb +9 -4
  75. data/lib/more/facets/module/class_extend.rb +2 -121
  76. data/lib/more/facets/ostruct.rb +9 -9
  77. data/lib/more/facets/pathlist.rb +1 -9
  78. data/lib/more/facets/pathname.rb +11 -4
  79. data/lib/more/facets/plugin_manager.rb +50 -0
  80. data/lib/more/facets/random.rb +25 -3
  81. data/lib/more/facets/roman.rb +174 -0
  82. data/lib/more/facets/semaphore.rb +92 -0
  83. data/lib/more/facets/shellwords.rb +21 -48
  84. data/lib/more/facets/succ.rb +1 -1
  85. data/meta/{modified → released} +0 -0
  86. data/meta/repository +1 -0
  87. data/meta/suite +1 -0
  88. data/meta/version +1 -1
  89. data/script/conflicts +63 -0
  90. data/script/methods +49 -0
  91. data/test/core/binding/test_caller.rb +11 -4
  92. data/test/core/enumerable/test_count.rb +19 -10
  93. data/test/core/enumerable/test_map_detect.rb +75 -0
  94. data/test/core/enumerable/test_take.rb +1 -1
  95. data/test/core/kernel/test_object_hexid.rb +2 -1
  96. data/test/core/proc/test_to_method.rb +1 -1
  97. data/test/core/string/test_cleanlines.rb +11 -0
  98. data/test/core/string/test_indent.rb +66 -4
  99. data/test/core/string/test_lines.rb +2 -1
  100. data/test/core/string/test_newlines.rb +13 -0
  101. data/test/core/time/test_change.rb +1 -1
  102. data/test/core/time/test_stamp.rb +4 -7
  103. data/test/core/unboundmethod/test_name.rb +1 -1
  104. data/test/more/test_basicobject.rb +1 -20
  105. data/test/more/test_class_extend.rb +7 -0
  106. data/test/more/test_continuation.rb +8 -6
  107. data/test/more/test_inheritor.rb +12 -6
  108. data/test/more/test_random.rb +19 -10
  109. data/test/more/test_shellwords.rb +33 -0
  110. metadata +60 -31
  111. data/TODO +0 -5
  112. data/doc/README.core +0 -102
  113. data/doc/README.more +0 -61
  114. data/doc/manual/about.rb +0 -47
  115. data/doc/manual/annotations.rdoc +0 -60
  116. data/doc/manual/associations.rdoc +0 -55
  117. data/doc/manual/blockups.rdoc +0 -101
  118. data/doc/manual/capsule.rdoc +0 -34
  119. data/doc/manual/command.rdoc +0 -177
  120. data/doc/manual/core.rdoc +0 -37
  121. data/doc/manual/faq.rdoc +0 -32
  122. data/doc/manual/typecast.html +0 -112
  123. data/lib/more/facets/capsule.rb +0 -258
  124. data/lib/more/facets/coroutine.rb +0 -159
  125. data/lib/more/facets/enumerablepass.rb +0 -3
  126. data/lib/more/facets/fileable.rb +0 -162
  127. data/lib/more/facets/progressbar.rb +0 -253
  128. data/lib/more/facets/recorder.rb +0 -108
  129. data/meta/releases +0 -14
  130. data/test/more/test_coroutine.rb +0 -46
@@ -0,0 +1,24 @@
1
+ class String
2
+
3
+ # Like index but returns an array of all index locations.
4
+ # The reuse flag allows the trailing portion of a match to be
5
+ # reused for subsquent matches.
6
+ #
7
+ # "abcabcabc".index_all('a') #=> [0,3,6]
8
+ #
9
+ # "bbb".index_all('bb', false) #=> [0]
10
+ # "bbb".index_all('bb', true) #=> [0,1]
11
+ #
12
+ # TODO: Culd probably be defined for Indexable in general too.
13
+
14
+ def index_all(s, reuse=false)
15
+ s = Regexp.new(Regexp.escape(s)) unless Regexp===s
16
+ ia = []; i = 0
17
+ while (i = index(s,i))
18
+ ia << i
19
+ i += (reuse ? 1 : $~[0].size)
20
+ end
21
+ ia
22
+ end
23
+
24
+ end
@@ -4,16 +4,13 @@ class String
4
4
 
5
5
  # Returns an array of characters.
6
6
  #
7
- # "abc\n123".lines #=> ["abc","123"]
8
- #
9
- # Note, this is not 100% compatible with 1.8.7+
10
- # which returns an enumerator instead of an array.
7
+ # "abc\n123".lines #=> ["abc\n","123"]
11
8
  #
12
9
  def lines(&blk)
13
10
  if block_given?
14
- self.split(/\n/).each(&blk)
11
+ each_line(&blk) #scan(/$.*?\n/).each(&blk)
15
12
  else
16
- self.split(/\n/)
13
+ Enumerator.new(self, :lines) #.split(/\n/)
17
14
  end
18
15
  end
19
16
 
@@ -8,9 +8,10 @@ class String
8
8
  # | margin controlled!
9
9
  # }.margin
10
10
  #
11
- #
12
11
  # NOTE: This may still need a bit of tweaking.
13
12
  #
13
+ # TODO: describe its limits and caveats and edge cases
14
+ #
14
15
  # CREDIT: Trans
15
16
 
16
17
  def margin(n=0)
@@ -0,0 +1,35 @@
1
+ require "facets/enumerator"
2
+
3
+ class String
4
+
5
+ # Returns an Enumerator for iterating over each
6
+ # line of the string, void of the termining newline
7
+ # character, in contrast to #lines which retains it.
8
+ #
9
+ def newlines(&block)
10
+ if block
11
+ scan(/^.*?$/) do |line|
12
+ block.call(line.chomp)
13
+ end
14
+ else
15
+ Enumerator.new(self) do |output|
16
+ scan(/^.*?$/) do |line|
17
+ output.yield(line.chomp)
18
+ end
19
+ end
20
+ end
21
+ end
22
+
23
+ end
24
+
25
+ =begin test
26
+
27
+ "a\nb\nc".newlines.class.must == Enumerator
28
+ "a\nb\nc".newlines.to_a.must == %w{a b c}
29
+
30
+ a = []
31
+ "a\nb\nc".newlines{|nl| a << nl}
32
+ a.must == %w{a b c}
33
+
34
+ =end
35
+
@@ -0,0 +1,14 @@
1
+ class String
2
+
3
+ # Treats +self+ and +path+ as representations
4
+ # of pathnames, joining thme together as a
5
+ # single path.
6
+ #
7
+ # 'home'/'trans' #=> 'home/trans'
8
+ #
9
+ def /(path)
10
+ File.join(self, path)
11
+ end
12
+
13
+ end
14
+
@@ -45,32 +45,12 @@ class String
45
45
 
46
46
  def range_of_line
47
47
  offset=0; charmap = []
48
- self.each do |line|
48
+ each_line do |line|
49
49
  charmap << (offset..(offset + line.length - 1))
50
50
  offset += line.length
51
51
  end
52
52
  charmap
53
53
  end
54
54
 
55
- # Like index but returns an array of all index locations.
56
- # The reuse flag allows the trailing portion of a match to be
57
- # reused for subsquent matches.
58
- #
59
- # "abcabcabc".index_all('a') #=> [0,3,6]
60
- #
61
- # "bbb".index_all('bb', false) #=> [0]
62
- # "bbb".index_all('bb', true) #=> [0,1]
63
- #
64
- # TODO: Culd probably be defined for Indexable in general too.
65
-
66
- def index_all(s, reuse=false)
67
- s = Regexp.new(Regexp.escape(s)) unless Regexp===s
68
- ia = []; i = 0
69
- while (i = index(s,i))
70
- ia << i
71
- i += (reuse ? 1 : $~[0].size)
72
- end
73
- ia
74
- end
75
-
76
55
  end
56
+
@@ -0,0 +1 @@
1
+ require 'facets/string/range'
@@ -0,0 +1 @@
1
+ require 'facets/string/range'
@@ -0,0 +1,92 @@
1
+ #require 'facets/string/cmp'
2
+ #require 'facets/blank'
3
+ #require 'facets/string/natcmp'
4
+
5
+ class String
6
+
7
+ # A fuzzy matching mechanism. Returns a score from 0-1,
8
+ # based on the number of shared edges.
9
+ # To be effective, the strings must be of length 2 or greater.
10
+ #
11
+ # "Alexsander".fuzzy_match( "Aleksander" ) #=> 0.9
12
+ #
13
+ # The way it works:
14
+ #
15
+ # * Converts each string into a "graph like" object, with edges
16
+ # "alexsander" -> [ alexsander, alexsand, alexsan ... lexsand ... san ... an, etc ]
17
+ # "aleksander" -> [ aleksander, aleksand ... etc. ]
18
+ # * Perform match, then remove any subsets from this matched set (i.e. a hit
19
+ # on "san" is a subset of a hit on "sander")
20
+ # Above example, once reduced -> [ ale, sander ]
21
+ # * See's how many of the matches remain, and calculates a score based
22
+ # on how many matches, their length, and compare to the length of the
23
+ # larger of the two words.
24
+ #
25
+ # Still a bit rough. Any suggestions for improvement are welcome.
26
+ #
27
+ # CREDIT: Derek Lewis.
28
+ #
29
+ def similarity(str_in)
30
+ return 0 if str_in == nil
31
+ return 1 if self == str_in
32
+
33
+ # Make a graph of each word (okay, so its not a true graph, but is similar)
34
+ graph_A = Array.new
35
+ graph_B = Array.new
36
+
37
+ # "graph" self
38
+ last = self.length
39
+ (0..last).each do |ff|
40
+ loc = self.length
41
+ break if ff == last - 1
42
+ wordB = (1..(last-1)).to_a.reverse!
43
+ if (wordB != nil)
44
+ wordB.each do |ss|
45
+ break if ss == ff
46
+ graph_A.push( "#{self[ff..ss]}" )
47
+ end
48
+ end
49
+ end
50
+
51
+ # "graph" input string
52
+ last = str_in.length
53
+ (0..last).each{ |ff|
54
+ loc = str_in.length
55
+ break if ff == last - 1
56
+ wordB = (1..(last-1)).to_a.reverse!
57
+ wordB.each do |ss|
58
+ break if ss == ff
59
+ graph_B.push( "#{str_in[ff..ss]}" )
60
+ end
61
+ }
62
+
63
+ # count how many of these "graph edges" we have that are the same
64
+ matches = graph_A & graph_B
65
+ #matches = Array.new
66
+ #graph_A.each do |aa|
67
+ # matches.push( aa ) if( graph_B.include?( aa ) )
68
+ #end
69
+
70
+ # For eliminating subsets, we want to start with the smallest hits.
71
+ matches.sort!{|x,y| x.length <=> y.length}
72
+
73
+ # eliminate any subsets
74
+ mclone = matches.dup
75
+ mclone.each_index do |ii|
76
+ reg = Regexp.compile( Regexp.escape(mclone[ii]) )
77
+ count = 0.0
78
+ matches.each{|xx| count += 1 if xx =~ reg}
79
+ matches.delete(mclone[ii]) if count > 1
80
+ end
81
+
82
+ score = 0.0
83
+ matches.each{ |mm| score += mm.length }
84
+ self.length > str_in.length ? largest = self.length : largest = str_in.length
85
+ return score/largest
86
+ end
87
+
88
+ # DEPRECATED alias
89
+ #alias_method :fuzzy_match, :similarity
90
+
91
+ end
92
+
@@ -2,10 +2,10 @@ class String
2
2
 
3
3
  unless method_defined?(:start_with?) # 1.8.7+
4
4
 
5
- # Does a string start with the given prefix.
5
+ # Does a string start with the given prefix?
6
6
  #
7
- # "hello".starts_with?("he") #=> true
8
- # "hello".starts_with?("to") #=> false
7
+ # "hello".start_with?("he") #=> true
8
+ # "hello".start_with?("to") #=> false
9
9
  #
10
10
  # CREDIT: Lucas Carlson, Blaine Cook
11
11
 
@@ -19,8 +19,8 @@ class String
19
19
 
20
20
  # Does a string end with the given suffix?
21
21
  #
22
- # "hello".ends_with?("lo") #=> true
23
- # "hello".ends_with?("to") #=> false
22
+ # "hello".end_with?("lo") #=> true
23
+ # "hello".end_with?("to") #=> false
24
24
  #
25
25
  # CREDIT: Lucas Carlson, Blaine Cook
26
26
 
@@ -31,7 +31,7 @@ class String
31
31
  end
32
32
 
33
33
  alias_method :starts_with?, :start_with?
34
- alias_method :ends_with? , :ends_with?
34
+ alias_method :ends_with? , :end_with?
35
35
 
36
36
  end
37
37
 
@@ -8,7 +8,7 @@ class String
8
8
  # CREDIT: Eliazar Parra
9
9
 
10
10
  def titlecase
11
- gsub(/\b\w/){$&.upcase}
11
+ gsub(/\b\w/){ $`[-1,1] == "'" ? $& : $&.upcase }
12
12
  end
13
13
 
14
14
  end
@@ -15,20 +15,29 @@ unless defined? BasicObject # just in case it already exists!
15
15
  # depend upon <tt>method_missing</tt> (e.g. dynamic proxies).
16
16
  class BasicObject
17
17
  class << self
18
-
19
18
  # Hide the method named +name+ in the BlankSlate class. Don't
20
19
  # hide +instance_eval+ or any method beginning with "__".
20
+ #
21
+ # According to 1.9.1 it should have only these methods:
22
+ #
23
+ # * #__send__
24
+ # * #instance_eval
25
+ # * #instance_exec
26
+ # * #equal?
27
+ # * #==
28
+ # * #!
29
+ # * #!=
30
+ #
31
+ # Seems to me it should have #__id__ too.
21
32
  def hide(name)
22
33
  undef_method name if
23
- instance_methods.include?(name.to_s) and
24
- name !~ /^(__|instance_eval)/
34
+ instance_methods.include?(name.to_s) and
35
+ name !~ /^(__|instance_eval$|instance_exec$|equal\?$|\=\=$)/
25
36
  end
26
37
  end
27
-
28
38
  instance_methods.each { |m| hide(m) }
29
39
  end
30
40
 
31
-
32
41
  # Since Ruby is very dynamic, methods added to the ancestors of
33
42
  # BlankSlate <em>after BlankSlate is defined</em> will show up in the
34
43
  # list of available BlankSlate methods. We handle this by defining a
@@ -42,7 +51,7 @@ unless defined? BasicObject # just in case it already exists!
42
51
  def method_added(name)
43
52
  blank_slate_method_added(name)
44
53
  return if self != Kernel
45
- BlankSlate.hide(name)
54
+ BasicObject.hide(name)
46
55
  end
47
56
  end
48
57
  end
@@ -56,18 +65,10 @@ unless defined? BasicObject # just in case it already exists!
56
65
  def method_added(name)
57
66
  blank_slate_method_added(name)
58
67
  return if self != Object
59
- BlankSlate.hide(name)
68
+ BasicObject.hide(name)
60
69
  end
61
70
  end
62
71
  end
63
72
 
64
73
  end
65
74
 
66
- unless defined? BlankSlate
67
-
68
- # ActiveSupport compatiable version of BasicObject
69
- # if not Ruby 1.9+ uses Jim Weirich's BlankSlate.
70
- BlankSlate = BasicObject
71
-
72
- end
73
-
@@ -1,2 +1,10 @@
1
1
  warn "Use BasicObject instead of BlankSlate for future versions."
2
2
  require 'facets/basicobject'
3
+
4
+
5
+ unless defined? BlankSlate
6
+ # ActiveSupport compatiable version of BasicObject
7
+ # if not Ruby 1.9+ uses Jim Weirich's BlankSlate.
8
+ BlankSlate = ::BasicObject
9
+ end
10
+
@@ -1 +1,126 @@
1
- require 'facets/module/class_extend'
1
+ # = Class Extension
2
+ #
3
+ # Normally when including modules, class/module methods are not
4
+ # extended. To achieve this behavior requires some clever
5
+ # Ruby Karate. Instead class_extension provides an easy to use
6
+ # and clean solution. Simply place the extending class methods
7
+ # in a block of the special module method #class_extension.
8
+ #
9
+ # module Mix
10
+ # def inst_meth
11
+ # puts 'inst_meth'
12
+ # end
13
+ #
14
+ # class_extend do
15
+ # def class_meth
16
+ # "Class Method!"
17
+ # end
18
+ # end
19
+ # end
20
+ #
21
+ # class X
22
+ # include Mix
23
+ # end
24
+ #
25
+ # X.class_meth #=> "Class Method!"
26
+ #
27
+ # == History
28
+ #
29
+ # Thanks to Trans, Nobu and Ulysses for their original on this concept.
30
+ #
31
+ # == Authors
32
+ #
33
+ # * Daniel Schierbeck
34
+ # * Thomas Sawyer
35
+ # * Nobu Nakada
36
+ # * Ulysses
37
+ #
38
+ # == Copying
39
+ #
40
+ # Copyright (c) 2006 Daniel Schierbeck
41
+ #
42
+ # Ruby License
43
+ #
44
+ # This module is free software. You may use, modify, and/or redistribute this
45
+ # software under the same terms as Ruby.
46
+ #
47
+ # This program is distributed in the hope that it will be useful, but WITHOUT
48
+ # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
49
+ # FOR A PARTICULAR PURPOSE.
50
+
51
+ #
52
+ class Module
53
+
54
+ alias_method :append_features_without_class_extension, :append_features
55
+
56
+ # Normally when including modules, class/module methods are not
57
+ # extended. To achieve this behavior requires some clever
58
+ # Ruby Karate. Instead #class_extend provides an easy to use
59
+ # and clean solution. Simply place the extending class methods
60
+ # in a block of the special module method #class_extend.
61
+ #
62
+ # module Mix
63
+ # def inst_meth
64
+ # puts 'inst_meth'
65
+ # end
66
+ #
67
+ # class_extend do
68
+ # def class_meth
69
+ # "Class Method!"
70
+ # end
71
+ # end
72
+ # end
73
+ #
74
+ # class X
75
+ # include Mix
76
+ # end
77
+ #
78
+ # X.class_meth #=> "Class Method!"
79
+ #
80
+ # NOTE: This old #class_extension version of this method
81
+ # did not extend the containing class automatically --it had
82
+ # to be done by hand. With #class_extend, that is no longer
83
+ # the case.
84
+ #
85
+ def class_extend(*mods, &block)
86
+ @class_extension ||= Module.new do
87
+ def self.append_features(mod)
88
+ append_features_without_class_extension(mod)
89
+ end
90
+ end
91
+ @class_extension.__send__(:include, *mods)
92
+ @class_extension.module_eval(&block) if block_given?
93
+ extend(@class_extension) # extend this module too
94
+ @class_extension
95
+ end
96
+
97
+ # TODO: DEPRECATE
98
+ alias_method :class_extension, :class_extend
99
+
100
+ #private :class_extend
101
+
102
+ # Override +append_features+ to handle class-inheritable extensions.
103
+ def append_features(mod)
104
+ append_features_without_class_extension(mod)
105
+ mod.extend(class_extend)
106
+ if mod.instance_of? Module
107
+ mod.__send__(:class_extend).__send__(:include, class_extend)
108
+ end
109
+ end
110
+
111
+ end
112
+
113
+ class Class
114
+ # For Class, #class_extend is the same as class_eval.
115
+ # The alternative is to "undef_method :class_extend",
116
+ # but this seems uneccessarily limited.
117
+ #
118
+ def class_extend(*mods, &block)
119
+ m = Module.new
120
+ m.__send__(:include, *mods)
121
+ m.module_eval(&block)
122
+ extend(m)
123
+ m
124
+ end
125
+ end
126
+