facets 2.7.0 → 2.8.0

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