facets 2.7.0 → 2.8.0
Sign up to get free protection for your applications and to get access to all the features.
- data/HISTORY.rdoc +135 -294
- data/MANIFEST +40 -91
- data/NOTES +1 -1
- data/README.rdoc +10 -8
- data/Rakefile +11 -34
- data/demo/{hook.rd → hook.rdoc} +2 -0
- data/demo/{scenario_require.rd → scenario_require.rdoc} +3 -0
- data/lib/core/facets-live.rb +7 -5
- data/lib/core/facets.rb +379 -359
- data/lib/core/facets/array/conjoin.rb +2 -2
- data/lib/core/facets/array/pad.rb +1 -1
- data/lib/core/facets/array/recursively.rb +2 -2
- data/lib/core/facets/array/splice.rb +1 -1
- data/lib/core/facets/binding/caller.rb +2 -4
- data/lib/core/facets/comparable/comparable.rb +2 -2
- data/lib/core/facets/dir/ascend.rb +3 -0
- data/lib/core/facets/dir/recurse.rb +4 -0
- data/lib/core/facets/duplicable.rb +6 -8
- data/lib/core/facets/enumerable/count.rb +22 -13
- data/lib/core/facets/enumerable/map_detect.rb +28 -0
- data/lib/core/facets/enumerable/mash.rb +13 -5
- data/lib/core/facets/enumerable/per.rb +3 -1
- data/lib/core/facets/hash/count.rb +14 -0
- data/lib/core/facets/hash/data.rb +14 -0
- data/lib/core/facets/kernel/__method__.rb +1 -1
- data/lib/core/facets/kernel/d.rb +9 -8
- data/lib/core/facets/kernel/eigenclass.rb +20 -0
- data/lib/core/facets/kernel/extend.rb +10 -0
- data/lib/core/facets/kernel/instance_class.rb +1 -0
- data/lib/core/facets/kernel/instance_variables.rb +6 -6
- data/lib/core/facets/kernel/meta_alias.rb +18 -0
- data/lib/core/facets/kernel/meta_class.rb +17 -0
- data/lib/core/facets/kernel/meta_def.rb +18 -0
- data/lib/core/facets/kernel/meta_eval.rb +18 -0
- data/lib/core/facets/kernel/object_hexid.rb +21 -6
- data/lib/core/facets/kernel/object_state.rb +4 -2
- data/lib/core/facets/kernel/populate.rb +3 -1
- data/lib/core/facets/kernel/with.rb +1 -1
- data/lib/core/facets/metaid.rb +6 -93
- data/lib/core/facets/module/class_def.rb +2 -0
- data/lib/core/facets/module/extend.rb +10 -11
- data/lib/core/facets/module/is.rb +5 -5
- data/lib/core/facets/module/module_def.rb +31 -0
- data/lib/core/facets/string/camelcase.rb +14 -12
- data/lib/core/facets/string/cleanlines.rb +35 -0
- data/lib/core/facets/string/edit_distance.rb +62 -0
- data/lib/core/facets/string/indent.rb +86 -4
- data/lib/core/facets/string/index_all.rb +24 -0
- data/lib/core/facets/string/lines.rb +3 -6
- data/lib/core/facets/string/margin.rb +2 -1
- data/lib/core/facets/string/newlines.rb +35 -0
- data/lib/core/facets/string/op_div.rb +14 -0
- data/lib/core/facets/string/range.rb +2 -22
- data/lib/core/facets/string/range_all.rb +1 -0
- data/lib/core/facets/string/range_of_line.rb +1 -0
- data/lib/core/facets/string/similarity.rb +92 -0
- data/lib/core/facets/string/start_with.rb +6 -6
- data/lib/core/facets/string/titlecase.rb +1 -1
- data/lib/more/facets/basicobject.rb +16 -15
- data/lib/more/facets/blankslate.rb +8 -0
- data/lib/more/facets/class_extend.rb +126 -1
- data/lib/more/facets/continuation.rb +53 -54
- data/lib/more/facets/dictionary.rb +9 -63
- data/lib/more/facets/erb.rb +63 -0
- data/lib/more/facets/filelist.rb +5 -5
- data/lib/more/facets/hashbuilder.rb +101 -0
- data/lib/more/facets/inheritor.rb +36 -45
- data/lib/more/facets/ini.rb +267 -0
- data/lib/more/facets/instance_eval.rb +4 -4
- data/lib/more/facets/ioredirect.rb +7 -60
- data/lib/more/facets/linkedlist.rb +195 -0
- data/lib/more/facets/matcher.rb +140 -0
- data/lib/more/facets/memoizer.rb +64 -0
- data/lib/more/facets/methodspace.rb +9 -4
- data/lib/more/facets/module/class_extend.rb +2 -121
- data/lib/more/facets/ostruct.rb +9 -9
- data/lib/more/facets/pathlist.rb +1 -9
- data/lib/more/facets/pathname.rb +11 -4
- data/lib/more/facets/plugin_manager.rb +50 -0
- data/lib/more/facets/random.rb +25 -3
- data/lib/more/facets/roman.rb +174 -0
- data/lib/more/facets/semaphore.rb +92 -0
- data/lib/more/facets/shellwords.rb +21 -48
- data/lib/more/facets/succ.rb +1 -1
- data/meta/{modified → released} +0 -0
- data/meta/repository +1 -0
- data/meta/suite +1 -0
- data/meta/version +1 -1
- data/script/conflicts +63 -0
- data/script/methods +49 -0
- data/test/core/binding/test_caller.rb +11 -4
- data/test/core/enumerable/test_count.rb +19 -10
- data/test/core/enumerable/test_map_detect.rb +75 -0
- data/test/core/enumerable/test_take.rb +1 -1
- data/test/core/kernel/test_object_hexid.rb +2 -1
- data/test/core/proc/test_to_method.rb +1 -1
- data/test/core/string/test_cleanlines.rb +11 -0
- data/test/core/string/test_indent.rb +66 -4
- data/test/core/string/test_lines.rb +2 -1
- data/test/core/string/test_newlines.rb +13 -0
- data/test/core/time/test_change.rb +1 -1
- data/test/core/time/test_stamp.rb +4 -7
- data/test/core/unboundmethod/test_name.rb +1 -1
- data/test/more/test_basicobject.rb +1 -20
- data/test/more/test_class_extend.rb +7 -0
- data/test/more/test_continuation.rb +8 -6
- data/test/more/test_inheritor.rb +12 -6
- data/test/more/test_random.rb +19 -10
- data/test/more/test_shellwords.rb +33 -0
- metadata +60 -31
- data/TODO +0 -5
- data/doc/README.core +0 -102
- data/doc/README.more +0 -61
- data/doc/manual/about.rb +0 -47
- data/doc/manual/annotations.rdoc +0 -60
- data/doc/manual/associations.rdoc +0 -55
- data/doc/manual/blockups.rdoc +0 -101
- data/doc/manual/capsule.rdoc +0 -34
- data/doc/manual/command.rdoc +0 -177
- data/doc/manual/core.rdoc +0 -37
- data/doc/manual/faq.rdoc +0 -32
- data/doc/manual/typecast.html +0 -112
- data/lib/more/facets/capsule.rb +0 -258
- data/lib/more/facets/coroutine.rb +0 -159
- data/lib/more/facets/enumerablepass.rb +0 -3
- data/lib/more/facets/fileable.rb +0 -162
- data/lib/more/facets/progressbar.rb +0 -253
- data/lib/more/facets/recorder.rb +0 -108
- data/meta/releases +0 -14
- data/test/more/test_coroutine.rb +0 -46
@@ -0,0 +1,18 @@
|
|
1
|
+
module Kernel
|
2
|
+
|
3
|
+
# Add method to a meta-class --i.e. a singleton method.
|
4
|
+
#
|
5
|
+
# class X; end
|
6
|
+
# X.meta_def(:x){"x"}
|
7
|
+
# X.x #=> "x"
|
8
|
+
#
|
9
|
+
# CREDIT: WhyTheLuckyStiff
|
10
|
+
|
11
|
+
def meta_def( name, &block )
|
12
|
+
meta_class do
|
13
|
+
define_method( name, &block )
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Kernel
|
2
|
+
|
3
|
+
|
4
|
+
# Evaluate code in a metaclass. This is equivalent to
|
5
|
+
# 'meta_class.instance_eval'.
|
6
|
+
#
|
7
|
+
# CREDIT: WhyTheLuckyStiff
|
8
|
+
|
9
|
+
def meta_eval(str=nil, &blk)
|
10
|
+
if str
|
11
|
+
meta_class.instance_eval(str)
|
12
|
+
else
|
13
|
+
meta_class.instance_eval(&blk)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
|
@@ -1,12 +1,27 @@
|
|
1
1
|
module Kernel
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
3
|
+
if RUBY_VERSION < "1.8.7"
|
4
|
+
|
5
|
+
# Returns the object id as a string in hexideciaml,
|
6
|
+
# which is how Ruby reports them with inspect.
|
7
|
+
#
|
8
|
+
# "ABC".object_hexid #=> "0x402d359c"
|
9
|
+
|
10
|
+
def object_hexid
|
11
|
+
return "0x" << (('%.x' % (2*self.__id__))[1..-1])
|
12
|
+
end
|
13
|
+
|
14
|
+
else
|
15
|
+
|
16
|
+
# Returns the object id as a string in hexideciaml,
|
17
|
+
# which is how Ruby reports them with inspect.
|
18
|
+
#
|
19
|
+
# "ABC".object_hexid #=> "0x402d359c"
|
20
|
+
|
21
|
+
def object_hexid
|
22
|
+
return "0x" << ('%.x' % (2*self.__id__)) #[1..-1]
|
23
|
+
end
|
7
24
|
|
8
|
-
def object_hexid
|
9
|
-
return "0x" << ('%.x' % (2*self.__id__)) #[1..-1]
|
10
25
|
end
|
11
26
|
|
12
27
|
end
|
@@ -1,5 +1,7 @@
|
|
1
1
|
class Object
|
2
|
-
# Get state of object.
|
2
|
+
# Get or set state of object.
|
3
|
+
#
|
4
|
+
# TODO: Would #instance_state be a more appropriate name?
|
3
5
|
def object_state(data=nil)
|
4
6
|
if data
|
5
7
|
instance_variables.each do |iv|
|
@@ -12,7 +14,7 @@ class Object
|
|
12
14
|
name = iv.to_s.sub(/^[@]/, '').to_sym
|
13
15
|
data[name] = instance_variable_get(iv)
|
14
16
|
end
|
15
|
-
|
17
|
+
data
|
16
18
|
end
|
17
19
|
end
|
18
20
|
|
@@ -18,7 +18,9 @@ module Kernel
|
|
18
18
|
# order of assignemnt.
|
19
19
|
#
|
20
20
|
# Using a hash or array will not raise an error if the
|
21
|
-
# accessor does not exits --it will simply be skipped.
|
21
|
+
# accessor does not exits -- it will simply be skipped.
|
22
|
+
#
|
23
|
+
# (See also: instance_vars.update, which sets instance variables directly, bypassing accessor method.)
|
22
24
|
#
|
23
25
|
# TODO: Better name, #set_with ?
|
24
26
|
|
data/lib/core/facets/metaid.rb
CHANGED
@@ -1,94 +1,7 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
# X.ynot? #=> y?
|
8
|
-
#
|
9
|
-
# CREDIT: Trans
|
10
|
-
|
11
|
-
def meta_alias(*args)
|
12
|
-
meta_class do
|
13
|
-
alias_method(*args)
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
# Evaluate code in a metaclass. This is equivalent to
|
18
|
-
# 'meta_class.instance_eval'.
|
19
|
-
#
|
20
|
-
# CREDIT: WhyTheLuckyStiff
|
21
|
-
|
22
|
-
def meta_eval(str=nil, &blk)
|
23
|
-
if str
|
24
|
-
meta_class.instance_eval(str)
|
25
|
-
else
|
26
|
-
meta_class.instance_eval(&blk)
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
# Add method to a meta-class --i.e. a singleton method.
|
31
|
-
#
|
32
|
-
# class X; end
|
33
|
-
# X.meta_def(:x){"x"}
|
34
|
-
# X.x #=> "x"
|
35
|
-
#
|
36
|
-
# CREDIT: WhyTheLuckyStiff
|
37
|
-
|
38
|
-
def meta_def( name, &block )
|
39
|
-
meta_class do
|
40
|
-
define_method( name, &block )
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
# Easy access to an object's "special" class,
|
45
|
-
# otherwise known as it's metaclass or singleton class.
|
46
|
-
|
47
|
-
def meta_class(&block)
|
48
|
-
if block_given?
|
49
|
-
(class << self; self; end).class_eval(&block)
|
50
|
-
else
|
51
|
-
(class << self; self; end)
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
alias_method :metaclass, :meta_class
|
56
|
-
|
57
|
-
# During this trying time when no one can get their
|
58
|
-
# techie catchwords to stick to the refrigerator no
|
59
|
-
# matter how hard they slap it # with the enchanted
|
60
|
-
# magnetic spatula, it’s good to know that the
|
61
|
-
# contrived phrases really do fly, graceful and
|
62
|
-
# unclasped and bearing north toward chilled shrimp.
|
63
|
-
# I know what my Hallowe’en pumpkin is going to say.
|
64
|
-
#
|
65
|
-
# -- why the lucky stiff
|
66
|
-
#
|
67
|
-
# CREDIT: WhyTheLuckyStiff
|
68
|
-
|
69
|
-
def eigenclass
|
70
|
-
(class << self; self; end)
|
71
|
-
end
|
72
|
-
|
73
|
-
end
|
74
|
-
|
75
|
-
|
76
|
-
class Module
|
77
|
-
|
78
|
-
# Defines an instance method within a class.
|
79
|
-
#
|
80
|
-
# CREDIT: WhyTheLuckyStiff
|
81
|
-
|
82
|
-
def class_def name, &blk
|
83
|
-
class_eval { define_method name, &blk }
|
84
|
-
end
|
85
|
-
|
86
|
-
protected :attr
|
87
|
-
protected :attr_reader
|
88
|
-
protected :attr_writer
|
89
|
-
protected :attr_accessor
|
90
|
-
protected :remove_method
|
91
|
-
protected :undef_method
|
92
|
-
|
93
|
-
end
|
1
|
+
require 'facets/kernel/meta_alias'
|
2
|
+
require 'facets/kernel/meta_class'
|
3
|
+
require 'facets/kernel/meta_def'
|
4
|
+
require 'facets/kernel/meta_eval'
|
5
|
+
require 'facets/kernel/eigenclass'
|
6
|
+
require 'facets/module/class_def'
|
94
7
|
|
@@ -1,11 +1,10 @@
|
|
1
|
-
class Module
|
2
|
-
|
3
|
-
alias_method :_extend, :extend
|
4
|
-
|
5
|
-
def extend(*mod, &blk)
|
6
|
-
_extend *mod unless mod.empty?
|
7
|
-
_extend Module.new(&blk) if blk
|
8
|
-
end
|
9
|
-
|
10
|
-
end
|
11
|
-
|
1
|
+
#class Module
|
2
|
+
#
|
3
|
+
# alias_method :_extend, :extend
|
4
|
+
#
|
5
|
+
# def extend(*mod, &blk)
|
6
|
+
# _extend *mod unless mod.empty?
|
7
|
+
# _extend Module.new(&blk) if blk
|
8
|
+
# end
|
9
|
+
#
|
10
|
+
#end
|
@@ -6,12 +6,12 @@ class Module
|
|
6
6
|
# class X ; end
|
7
7
|
# class Y < X ; end
|
8
8
|
#
|
9
|
-
#
|
9
|
+
# Y.is?(X) #=> true
|
10
10
|
#
|
11
11
|
# CREDIT: Trans
|
12
12
|
|
13
13
|
def is?(base)
|
14
|
-
ancestors.slice(1..-1).include?(base)
|
14
|
+
Module===base && ancestors.slice(1..-1).include?(base)
|
15
15
|
end
|
16
16
|
|
17
17
|
# An alias for #include.
|
@@ -22,8 +22,6 @@ class Module
|
|
22
22
|
#
|
23
23
|
# CREDIT: Trans
|
24
24
|
|
25
|
-
#alias_method :is, :include
|
26
|
-
|
27
25
|
def is(*mods)
|
28
26
|
mods.each do |mod|
|
29
27
|
if mod.const_defined?(:Self)
|
@@ -38,9 +36,11 @@ class Module
|
|
38
36
|
include(*mods)
|
39
37
|
end
|
40
38
|
|
39
|
+
#alias_method :is, :include
|
40
|
+
|
41
41
|
# Expirmental idea for #is.
|
42
42
|
#
|
43
|
-
# If the module has #
|
43
|
+
# If the module has #append_feature_function
|
44
44
|
# defined, this will use that instead of #include.
|
45
45
|
#
|
46
46
|
# def is(*modules)
|
@@ -0,0 +1,31 @@
|
|
1
|
+
class Module
|
2
|
+
|
3
|
+
# Defines an instance method within a class/module.
|
4
|
+
#
|
5
|
+
# CREDIT: WhyTheLuckyStiff
|
6
|
+
|
7
|
+
def class_def name, &blk
|
8
|
+
class_eval { define_method name, &blk }
|
9
|
+
end
|
10
|
+
|
11
|
+
# Defines an instance method within a class/module.
|
12
|
+
#
|
13
|
+
# CREDIT: WhyTheLuckyStiff
|
14
|
+
|
15
|
+
def module_def name, &blk
|
16
|
+
module_eval { define_method name, &blk }
|
17
|
+
end
|
18
|
+
|
19
|
+
#--
|
20
|
+
# TODO: Why are we making these protected,
|
21
|
+
# and where should these really go in Facets?
|
22
|
+
#++
|
23
|
+
protected :attr
|
24
|
+
protected :attr_reader
|
25
|
+
protected :attr_writer
|
26
|
+
protected :attr_accessor
|
27
|
+
protected :remove_method
|
28
|
+
protected :undef_method
|
29
|
+
|
30
|
+
end
|
31
|
+
|
@@ -16,18 +16,20 @@ class String
|
|
16
16
|
# "Camel_case".camelcase(false) #=> "camelCase"
|
17
17
|
#
|
18
18
|
# TODO: Is this the best approach? Should lowerCamelCase be default instead?
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
19
|
+
unless method_defined?(:camelcase)
|
20
|
+
def camelcase(first_letter=nil)
|
21
|
+
case first_letter
|
22
|
+
when :upper, true
|
23
|
+
upper_camelcase
|
24
|
+
when :lower, false
|
25
|
+
lower_camelcase
|
26
|
+
else
|
27
|
+
str = dup
|
28
|
+
str.gsub!(/\/(.?)/){ "::#{$1.upcase}" } # NOT SO SURE ABOUT THIS
|
29
|
+
str.gsub!(/(?:_+|-+)([a-z])/){ $1.upcase }
|
30
|
+
#str.gsub!(/(\A|\s)([a-z])/){ $1 + $2.upcase }
|
31
|
+
str
|
32
|
+
end
|
31
33
|
end
|
32
34
|
end
|
33
35
|
|
@@ -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, stripped of whitespace on
|
7
|
+
# either side.
|
8
|
+
#
|
9
|
+
def cleanlines(&block)
|
10
|
+
if block
|
11
|
+
scan(/^.*?$/) do |line|
|
12
|
+
block.call(line.strip)
|
13
|
+
end
|
14
|
+
else
|
15
|
+
Enumerator.new(self) do |output|
|
16
|
+
scan(/^.*?$/) do |line|
|
17
|
+
output.yield(line.strip)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
=begin test
|
26
|
+
|
27
|
+
"a \n b \n c".newlines.class.must == Enumerator
|
28
|
+
"a \n b \n c".newlines.to_a.must == %w{a b c}
|
29
|
+
|
30
|
+
a = []
|
31
|
+
"a \n b \n c".newlines{|nl| a << nl}
|
32
|
+
a.must == %w{a b c}
|
33
|
+
|
34
|
+
=end
|
35
|
+
|
@@ -0,0 +1,62 @@
|
|
1
|
+
class String
|
2
|
+
|
3
|
+
# Levenshtein distance algorithm implementation for Ruby, with UTF-8 support.
|
4
|
+
#
|
5
|
+
# The Levenshtein distance is a measure of how similar two strings s and t are,
|
6
|
+
# calculated as the number of deletions/insertions/substitutions needed to
|
7
|
+
# transform s into t. The greater the distance, the more the strings differ.
|
8
|
+
#
|
9
|
+
# The Levenshtein distance is also sometimes referred to as the
|
10
|
+
# easier-to-pronounce-and-spell 'edit distance'.
|
11
|
+
#
|
12
|
+
# Calculate the Levenshtein distance between two strings +self+ and +str2+.
|
13
|
+
# +self+ and +str2+ should be ASCII, UTF-8, or a one-byte-per character encoding
|
14
|
+
# such as ISO-8859-*.
|
15
|
+
#
|
16
|
+
# The strings will be treated as UTF-8 if $KCODE is set appropriately (i.e. 'u').
|
17
|
+
# Otherwise, the comparison will be performed byte-by-byte. There is no specific support
|
18
|
+
# for Shift-JIS or EUC strings.
|
19
|
+
#
|
20
|
+
# When using Unicode text, be aware that this algorithm does not perform normalisation.
|
21
|
+
# If there is a possibility of different normalised forms being used, normalisation
|
22
|
+
# should be performed beforehand.
|
23
|
+
#
|
24
|
+
# CREDIT: Paul Battley
|
25
|
+
#
|
26
|
+
def edit_distance(str2)
|
27
|
+
str1 = self
|
28
|
+
if $KCODE =~ /^U/i
|
29
|
+
unpack_rule = 'U*'
|
30
|
+
else
|
31
|
+
unpack_rule = 'C*'
|
32
|
+
end
|
33
|
+
s = str1.unpack(unpack_rule)
|
34
|
+
t = str2.unpack(unpack_rule)
|
35
|
+
n = s.length
|
36
|
+
m = t.length
|
37
|
+
return m if (0 == n)
|
38
|
+
return n if (0 == m)
|
39
|
+
|
40
|
+
d = (0..m).to_a
|
41
|
+
x = nil
|
42
|
+
|
43
|
+
(0...n).each do |i|
|
44
|
+
e = i+1
|
45
|
+
(0...m).each do |j|
|
46
|
+
cost = (s[i] == t[j]) ? 0 : 1
|
47
|
+
x = [
|
48
|
+
d[j+1] + 1, # insertion
|
49
|
+
e + 1, # deletion
|
50
|
+
d[j] + cost # substitution
|
51
|
+
].min
|
52
|
+
d[j] = e
|
53
|
+
e = x
|
54
|
+
end
|
55
|
+
d[m] = x
|
56
|
+
end
|
57
|
+
|
58
|
+
return x
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
|
@@ -3,13 +3,13 @@ class String
|
|
3
3
|
# Indent left or right by n spaces.
|
4
4
|
# (This used to be called #tab and aliased as #indent.)
|
5
5
|
#
|
6
|
-
# CREDIT: Gavin Sinclair, Trans
|
6
|
+
# CREDIT: Gavin Sinclair, Trans, Tyler Rick
|
7
7
|
|
8
|
-
def indent(n)
|
8
|
+
def indent(n, c=' ')
|
9
9
|
if n >= 0
|
10
|
-
gsub(/^/,
|
10
|
+
gsub(/^/, c * n)
|
11
11
|
else
|
12
|
-
gsub(
|
12
|
+
gsub(/^#{Regexp.escape(c)}{0,#{-n}}/, "")
|
13
13
|
end
|
14
14
|
end
|
15
15
|
|
@@ -23,3 +23,85 @@ class String
|
|
23
23
|
|
24
24
|
end
|
25
25
|
|
26
|
+
|
27
|
+
# _____ _
|
28
|
+
# |_ _|__ ___| |_
|
29
|
+
# | |/ _ \/ __| __|
|
30
|
+
# | | __/\__ \ |_
|
31
|
+
# |_|\___||___/\__|
|
32
|
+
#
|
33
|
+
=begin test
|
34
|
+
require 'test/unit'
|
35
|
+
|
36
|
+
class TC_String_Indent < Test::Unit::TestCase
|
37
|
+
|
38
|
+
def test_positive_indent
|
39
|
+
assert_equal ' xyz', "xyz". indent(4)
|
40
|
+
assert_equal ' xyz', " xyz".indent(2)
|
41
|
+
end
|
42
|
+
|
43
|
+
def test_multi_line_positive_indent
|
44
|
+
assert_equal " abc\n" +
|
45
|
+
" xyz" ,
|
46
|
+
("abc\n" +
|
47
|
+
"xyz" ).indent(2)
|
48
|
+
end
|
49
|
+
|
50
|
+
def test_0_indent
|
51
|
+
assert_equal 'xyz', 'xyz'.indent(0)
|
52
|
+
end
|
53
|
+
|
54
|
+
def test_negative_indent
|
55
|
+
assert_equal ' xyz', ' xyz'.indent(-2)
|
56
|
+
assert_equal 'xyz', ' xyz'. indent(-2)
|
57
|
+
end
|
58
|
+
|
59
|
+
def test_multi_line_negative_indent
|
60
|
+
assert_equal " abc\n" +
|
61
|
+
" xyz" ,
|
62
|
+
(" abc\n" +
|
63
|
+
" xyz" ).indent(-2)
|
64
|
+
end
|
65
|
+
|
66
|
+
def test_outdent_is_alias_for_negative_indent
|
67
|
+
assert_equal 'xyz', ' xyz'.outdent(2)
|
68
|
+
end
|
69
|
+
|
70
|
+
def test_negative_indent_more_than_is_possible
|
71
|
+
assert_equal 'xyz', ' xyz'.indent(-3)
|
72
|
+
end
|
73
|
+
|
74
|
+
#-----------------------------------
|
75
|
+
# Using a character other than space
|
76
|
+
|
77
|
+
def test_nonspace_positive__indent
|
78
|
+
assert_equal '----xyz', "xyz".indent(4, '-')
|
79
|
+
end
|
80
|
+
|
81
|
+
def test_nonspace_0_indent
|
82
|
+
assert_equal 'xyz', 'xyz'.indent(0, '-')
|
83
|
+
end
|
84
|
+
|
85
|
+
def test_nonspace_negative_indent_nonmatching_character
|
86
|
+
assert_equal ' xyz', ' xyz'.indent(-2, '-')
|
87
|
+
assert_equal ' xyz', ' xyz'. indent(-2, '-')
|
88
|
+
end
|
89
|
+
|
90
|
+
def test_nonspace_negative_indent
|
91
|
+
assert_equal '--xyz', '----xyz'.indent(-2, '-')
|
92
|
+
assert_equal 'xyz', '--xyz'.indent(-2, '-')
|
93
|
+
end
|
94
|
+
|
95
|
+
def test_special_regexp_characters_are_escaped
|
96
|
+
# make sure . is treated as a literal '.' and not an "any character" wildcard
|
97
|
+
assert_equal ' xyz', ' xyz'.indent(-2, '.')
|
98
|
+
assert_equal 'xyz', '..xyz'.indent(-2, '.')
|
99
|
+
|
100
|
+
assert_equal ' xyz', ' xyz'.indent(-2, '^')
|
101
|
+
assert_equal 'xyz', '^^xyz'.indent(-2, '^')
|
102
|
+
|
103
|
+
assert_equal ' xyz', ' xyz'.indent(-2, '*')
|
104
|
+
assert_equal 'xyz', '**xyz'.indent(-2, '*')
|
105
|
+
end
|
106
|
+
end
|
107
|
+
=end
|