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.
- 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
|