Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

added with_indent parameter to strip_heredoc #7263

Closed
wants to merge 2 commits into from

3 participants

@acesuares

strip_heredoc strips all leading spaces/tabs from a heredoc.

But there are situations when you want to retain a certain indent, for instance, when inserting something in config/environments/production.rb

Example:

module Module
  class Creator < Thor
    desc "dostuff NAME", "do stuff to NAME"
    def dostuff(name)
      insert_into_file "config/environments/production.rb", <<-HEREDOC.strip_heredoc(2), :before => "end\n"
        # mailer settings
        config.action_mailer.smtp_settings = {
          :address => 'YOURMAILSERVER',
          :enable_starttls_auto => true,
          :password => 'YOURPASSWORD',
          :user_name => 'YOURUSERNAME'
        }

      HEREDOC
    end   
  end   
end   
```ruby

The result is that the inserted text is indented by 2 spaces, to align with the rest of production.rb.

Cheers
ace
@fxn
Owner
fxn commented

The feature looks good to me, would you please update the documentation in the AS guide? I wonder if one would expect the indent to be inserted with the same char used in the literal. I mean, use space or tab depending on what the code uses. If there's a mix of them the chosen one is undefined.

Alternatively a third optional argument could specify the char, and the default would be chosen according to what the literal uses.

@acesuares

What is 'the literal'? I understand the additions, very good, I can do them but what is 'the literal'?

@avit

@acesuares the literal = the heredoc string value.

@acesuares

Ok thx @avit, now I understand better. @fxn I think it's not a good idea, to try to guess the 'same character' as the literal uses, especially since the gsub in the original heredoc replaces spaces as wel as tabs. which is in itself interesting.
_ = space - = tab:

_-LINE1
_--_LINE2
_-__LINE3
__LINE4

strip_heredoc will produce:

LINE1
-_LINE2
__LINE3
LINE4

Which is interesting at the least.

So, I think guessing what the original literal used for indentation is not very reliable. Adding an extra option as to what character to use when indenting, it's easy to do, and then strip_heredoc can be used to indent with stars, stripes, BELL characters etc etc... not sure if we need that. Please advice.

@fxn
Owner
fxn commented

The original method works well with spaces and tabs. That is, if the string uses spaces, it unindents as many spaces as needed, and the same goes with tabs. That is, as long as the string uses either spaces or tabs for indentation. If you mix them, then whatever happens is undefined.

This patch goes beyond indentation removal, it inserts indentation. I believe that for it to be complete it should also understand both styles out of the box.

@fxn
Owner
fxn commented

Oh, let me add that by explicitly saying that the behaviour is undefined if spaces and tabs are mixed you can ease the implementation: If there's any indentation at all, you pick the first whitespace char in the first indent chunk. If there's none, you default to space. An explicit third argument takes precendence over all that and skips the very computation.

See what I mean?

@acesuares

@Fxn, I see what you mean, but what happens when you mix tabs and spaces, is not undefined (correct me if I am wrong). strip_heredoc determines how many tabs and/or spaces there are on the first line; let's say it's two spaces and a tab. Then it will delete the first three tabs and/or spaces from each line. I will leave other spaces and/or tabs after the first three tabs and/or spaces alone.

I propose not to find out what the first character of the first line is; instead default to space, and if the extra parameter is there, then use that.

What do you think, should strip_heredoc be limited to spaces and tabs? Because if that's the case, then tabs=false should be the default extra parameter. Like this: strip_heredoc(2,true) for adding two tabs to the beginning of the stripped text (irregardless if the heredoc has tabs, space or mixed tabs and spaces).

?

@fxn
Owner
fxn commented

@acesuares with undefined behavior we mean we don't say what is the method going to do. In theory it could erase the hard disk of the user. It won't, and sure will do something and be deterministic, but the method does not commit to anything.

The contract is:

  • If the string uses spaces, the method does what you'd expect by default.

  • If the string uses tabs, the method does what you'd expect by default.

  • If the string uses tabs and spaces mixed: this input is unsupported, undefined behavior.

With respect to the char to indent, having a flag as third argument is a good idea. It would be a three-valued flag, though, which is a little unusual. We would need to understand "guess it (default)" (nil), from "use spaces" (false), and "use tabs" (true). Not 100% sure I like that interface, I like flags to be interpreted as per the Ruby definition of true and false.

@acesuares

I would greatly appreciate it if you would write the code to find out what the 'guess' character is. Also, what should the parameter be named? character=nil come to mind.

@fxn
Owner
fxn commented

@acesuares sure, let me take the baton.

@acesuares

@Fxn :-) Well, just that one line that determines the 'guess' character, and the name of the parameter will do (guess=nil)???

@fxn
Owner
fxn commented

I am about to push the patch. In the end I went for a dedicated helper #indent, once written all that seemed too much responsibilities for strip_heredoc. You'll see.

@fxn fxn closed this in 2f58795
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Aug 4, 2012
  1. added with_indent parameter to strip_heredoc

    Ace Suares authored
  2. updated ActiveSupport guide for strip_heredoc

    Ace Suares authored
This page is out of date. Refresh to see the latest.
View
8 activesupport/lib/active_support/core_ext/string/strip.rb
@@ -19,8 +19,12 @@ class String
#
# Technically, it looks for the least indented line in the whole string, and removes
# that amount of leading whitespace.
- def strip_heredoc
+ #
+ # Use strip_heredoc(2) if you want the result to be preceded by 2 spaces. For instance, if you want to
+ # insert something in a place that already has two spaces indent, like config/environments/production.rb
+ #
+ def strip_heredoc(with_indent = 0)
indent = scan(/^[ \t]*(?=\S)/).min.try(:size) || 0
- gsub(/^[ \t]{#{indent}}/, '')
+ gsub(/^[ \t]{#{indent}}/, ' ' * with_indent)
end
end
View
31 activesupport/test/core_ext/string_ext_test.rb
@@ -52,6 +52,37 @@ def test_strip_heredoc_on_a_regular_indented_heredoc_with_blank_lines
EOS
end
+ def test_strip_heredoc_with_indent_on_an_empty_string
+ assert_equal ' ', ''.strip_heredoc(2)
+ end
+
+ def test_strip_heredoc_with_indent_on_a_string_with_no_lines
+ assert_equal ' x', 'x'.strip_heredoc(2)
+ assert_equal ' x', ' x'.strip_heredoc(2)
+ end
+
+ def test_strip_heredoc_with_indent_on_a_heredoc_with_no_margin
+ assert_equal " foo\n bar", "foo\nbar".strip_heredoc(2)
+ assert_equal " foo\n bar", "foo\n bar".strip_heredoc(2)
+ end
+
+ def test_strip_heredoc_with_indent_on_a_regular_indented_heredoc
+ assert_equal " foo\n bar\n baz\n", <<-EOS.strip_heredoc(2)
+ foo
+ bar
+ baz
+ EOS
+ end
+
+ def test_strip_heredoc_with_indent_on_a_regular_indented_heredoc_with_blank_lines
+ assert_equal " foo\n bar\n\n baz\n", <<-EOS.strip_heredoc(2)
+ foo
+ bar
+
+ baz
+ EOS
+ end
+
def test_pluralize
SingularToPlural.each do |singular, plural|
assert_equal(plural, singular.pluralize)
View
24 guides/source/active_support_core_extensions.textile
@@ -1320,8 +1320,28 @@ end
the user would see the usage message aligned against the left margin.
-Technically, it looks for the least indented line in the whole string, and removes
-that amount of leading whitespace.
+If for some reason the message needs to be indented, then specify the number of spaces
+as a parameter.
+
+For example in
+
+<ruby>
+if options[:usage]
+ puts <<-USAGE.strip_heredoc(2)
+ This command does such and such.
+
+ Supported options are:
+ -h This message
+ ...
+ USAGE
+end
+</ruby>
+
+the user would see the usage message aligned 2 spaces from the left margin.
+
+Technically, strip_heredoc looks for the least indented line in the whole string, and
+removes that amount of leading whitespace, and then adds the number of spaces specified in the
+parameter to the beginning of each line.
NOTE: Defined in +active_support/core_ext/string/strip.rb+.
Something went wrong with that request. Please try again.