aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--activesupport/CHANGELOG.md2
-rw-r--r--activesupport/lib/active_support/core_ext/string.rb1
-rw-r--r--activesupport/lib/active_support/core_ext/string/indent.rb43
-rw-r--r--activesupport/test/core_ext/string_ext_test.rb56
-rw-r--r--guides/source/active_support_core_extensions.textile35
5 files changed, 137 insertions, 0 deletions
diff --git a/activesupport/CHANGELOG.md b/activesupport/CHANGELOG.md
index 5fcea299f8..70bd1bf4d3 100644
--- a/activesupport/CHANGELOG.md
+++ b/activesupport/CHANGELOG.md
@@ -1,5 +1,7 @@
## Rails 4.0.0 (unreleased) ##
+* Add String#indent. *fxn & Ace Suares*
+
* Inflections can now be defined per locale. `singularize` and `pluralize` accept locale as an extra argument. *David Celis*
* `Object#try` will now return nil instead of raise a NoMethodError if the receiving object does not implement the method, but you can still get the old behavior by using the new `Object#try!` *DHH*
diff --git a/activesupport/lib/active_support/core_ext/string.rb b/activesupport/lib/active_support/core_ext/string.rb
index fb36262528..ad864765a3 100644
--- a/activesupport/lib/active_support/core_ext/string.rb
+++ b/activesupport/lib/active_support/core_ext/string.rb
@@ -10,3 +10,4 @@ require 'active_support/core_ext/string/output_safety'
require 'active_support/core_ext/string/exclude'
require 'active_support/core_ext/string/strip'
require 'active_support/core_ext/string/inquiry'
+require 'active_support/core_ext/string/indent'
diff --git a/activesupport/lib/active_support/core_ext/string/indent.rb b/activesupport/lib/active_support/core_ext/string/indent.rb
new file mode 100644
index 0000000000..afc3032272
--- /dev/null
+++ b/activesupport/lib/active_support/core_ext/string/indent.rb
@@ -0,0 +1,43 @@
+class String
+ # Same as +indent+, except it indents the receiver in-place.
+ #
+ # Returns the indented string, or +nil+ if there was nothing to indent.
+ def indent!(amount, indent_string=nil, indent_empty_lines=false)
+ indent_string = indent_string || self[/^[ \t]/] || ' '
+ re = indent_empty_lines ? /^/ : /^(?!$)/
+ gsub!(re, indent_string * amount)
+ end
+
+ # Indents the lines in the receiver:
+ #
+ # <<EOS.indent(2)
+ # def some_method
+ # some_code
+ # end
+ # EOS
+ # # =>
+ # def some_method
+ # some_code
+ # end
+ #
+ # The second argument, +indent_string+, specifies which indent string to
+ # use. The default is +nil+, which tells the method to make a guess by
+ # peeking at the first indented line, and fallback to a space if there is
+ # none.
+ #
+ # " foo".indent(2) # => " foo"
+ # "foo\n\t\tbar".indent(2) # => "\t\tfoo\n\t\t\t\tbar"
+ # "foo".indent(2, "\t") # => "\t\tfoo"
+ #
+ # While +indent_string+ is tipically one space or tab, it may be any string.
+ #
+ # The third argument, +indent_empty_lines+, is a flag that says whether
+ # empty lines should be indented. Default is false.
+ #
+ # "foo\n\nbar".indent(2) # => " foo\n\n bar"
+ # "foo\n\nbar".indent(2, nil, true) # => " foo\n \n bar"
+ #
+ def indent(amount, indent_string=nil, indent_empty_lines=false)
+ dup.tap {|_| _.indent!(amount, indent_string, indent_empty_lines)}
+ end
+end
diff --git a/activesupport/test/core_ext/string_ext_test.rb b/activesupport/test/core_ext/string_ext_test.rb
index 3b08ebe35f..dc5ae0eafc 100644
--- a/activesupport/test/core_ext/string_ext_test.rb
+++ b/activesupport/test/core_ext/string_ext_test.rb
@@ -9,6 +9,7 @@ require 'active_support/core_ext/string'
require 'active_support/time'
require 'active_support/core_ext/string/strip'
require 'active_support/core_ext/string/output_safety'
+require 'active_support/core_ext/string/indent'
module Ace
module Base
@@ -521,3 +522,58 @@ class StringExcludeTest < ActiveSupport::TestCase
assert_equal true, 'foo'.exclude?('p')
end
end
+
+class StringIndentTest < ActiveSupport::TestCase
+ test 'does not indent strings that only contain newlines (edge cases)' do
+ ['', "\n", "\n" * 7].each do |str|
+ assert_nil str.indent!(8)
+ assert_equal str, str.indent(8)
+ assert_equal str, str.indent(1, "\t")
+ end
+ end
+
+ test "by default, indents with spaces if the existing indentation uses them" do
+ assert_equal " foo\n bar", "foo\n bar".indent(4)
+ end
+
+ test "by default, indents with tabs if the existing indentation uses them" do
+ assert_equal "\tfoo\n\t\t\bar", "foo\n\t\bar".indent(1)
+ end
+
+ test "by default, indents with spaces as a fallback if there is no indentation" do
+ assert_equal " foo\n bar\n baz", "foo\nbar\nbaz".indent(3)
+ end
+
+ # Nothing is said about existing indentation that mixes spaces and tabs, so
+ # there is nothing to test.
+
+ test 'uses the indent char if passed' do
+ assert_equal <<EXPECTED, <<ACTUAL.indent(4, '.')
+.... def some_method(x, y)
+.... some_code
+.... end
+EXPECTED
+ def some_method(x, y)
+ some_code
+ end
+ACTUAL
+
+ assert_equal <<EXPECTED, <<ACTUAL.indent(2, '&nbsp;')
+&nbsp;&nbsp;&nbsp;&nbsp;def some_method(x, y)
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;some_code
+&nbsp;&nbsp;&nbsp;&nbsp;end
+EXPECTED
+&nbsp;&nbsp;def some_method(x, y)
+&nbsp;&nbsp;&nbsp;&nbsp;some_code
+&nbsp;&nbsp;end
+ACTUAL
+ end
+
+ test "does not indent blank lines by default" do
+ assert_equal " foo\n\n bar", "foo\n\nbar".indent(1)
+ end
+
+ test 'indents blank lines if told so' do
+ assert_equal " foo\n \n bar", "foo\n\nbar".indent(1, nil, true)
+ end
+end
diff --git a/guides/source/active_support_core_extensions.textile b/guides/source/active_support_core_extensions.textile
index 66de6fd310..109228f8c7 100644
--- a/guides/source/active_support_core_extensions.textile
+++ b/guides/source/active_support_core_extensions.textile
@@ -1325,6 +1325,41 @@ that amount of leading whitespace.
NOTE: Defined in +active_support/core_ext/string/strip.rb+.
+h4. +indent+
+
+Indents the lines in the receiver:
+
+<ruby>
+<<EOS.indent(2)
+def some_method
+ some_code
+end
+EOS
+# =>
+ def some_method
+ some_code
+ end
+</ruby>
+
+The second argument, +indent_string+, specifies which indent string to use. The default is +nil+, which tells the method to make an educated guess peeking at the first indented line, and fallback to a space if there is none.
+
+<ruby>
+" foo".indent(2) # => " foo"
+"foo\n\t\tbar".indent(2) # => "\t\tfoo\n\t\t\t\tbar"
+"foo".indent(2, "\t") # => "\t\tfoo"
+</ruby>
+
+While +indent_string+ is tipically one space or tab, it may be any string.
+
+The third argument, +indent_empty_lines+, is a flag that says whether empty lines should be indented. Default is false.
+
+<ruby>
+"foo\n\nbar".indent(2) # => " foo\n\n bar"
+"foo\n\nbar".indent(2, nil, true) # => " foo\n \n bar"
+</ruby>
+
+The +indent!+ method performs indentation in-place.
+
h4. Access
h5. +at(position)+