Gem-packed script with DATA section does not work

The attached minimal gem contains a script that reads "Hello World!"
from its DATA section and then prints it.
The script works, but after installing (sudo gem install
datasection.gemspec), the wrapper in /usr/local/bin does not see the
DATA section:

$ datasection
/usr/local/lib/ruby/gems/1.9.1/gems/datasection-0.01/bin/datasection:2:in `<top
(required)>': uninitialized constant DATA (NameError)
  from /usr/local/bin/datasection:19:in `load'
  from /usr/local/bin/datasection:19:in `<main>'

In my actual script the DATA section is planned to contain a much larger
erb-template and it seems not very elegant to put those as strings in
the script.

datasection-0.01.gem (3 KB)

···

--
Wybo

DATA points to the contents after the __END__ directive of the executable
script that acts as an entry point (is not per file).

RubyGems wraps gem's executables with its own executables. Those wrappers
know where's the gem executable located, and also understand version
selection as an underscored argument. So, in a gem, the very gem's
executables are not the main files because of this indirection.

Please can some one show me how to stop getting emails from
list@ruby-forum.com

···

--
Posted via http://www.ruby-forum.com/.

That's clear, but does that mean there's no workaround?
Can Ruby not be told that the DATA section is somewhere else?

···

On 2012-04-23 11:39, Xavier Noria wrote:

DATA points to the contents after the __END__ directive of the
executable script that acts as an entry point (is not per file).

RubyGems wraps gem's executables with its own executables. Those
wrappers know where's the gem executable located, and also understand
version selection as an underscored argument. So, in a gem, the very
gem's executables are not the main files because of this indirection.

--
Wybo

no one knows how we can do it. (:

···

On Mon, Apr 23, 2012 at 6:29 PM, Billy Alcazar <lists@ruby-forum.com> wrote:

Please can some one show me how to stop getting emails from
list@ruby-forum.com

--
Posted via http://www.ruby-forum.com/\.

--
*Ender Ahmet Yurt *
*www.enderahmetyurt.com*

That's clear, but does that mean there's no workaround?

Can Ruby not be told that the DATA section is somewhere else?

There's no workaround related to the DATA constant itself, it's defined
only for the main file.

You could of course switch to regular Ruby, for example throwing at the end
of the script:

    BEGIN {
      require 'stringio'
      DATA = StringIO.new(<<EOS)
      ...
      EOS
    }

That'd work because the main file is not going to define DATA (RubyGems
does not generate __END__), so the constant is undefined. You could also
scan __FILE__ in a BEGIN block looking for __END__ by hand to fully emulate
the feature.

The BEGIN block is needed because in the original DATA feature you get the
constant defined in the top-level right away if __END__ is present.

Well just giving some ideas, the main point is that you need to do it in
Ruby.

···

On Mon, Apr 23, 2012 at 1:49 PM, Wybo Dekker <wybo@xs4all.nl> wrote:

What do you mean? The instructions are right here:

http://www.ruby-lang.org/en/community/mailing-lists/

···

On Mon, Apr 23, 2012 at 11:37 AM, Ender Ahmet Yurt <enderyurt@gmail.com> wrote:

no one knows how we can do it. (:

--
Darryl L. Pierce <mcpierce@gmail.com>
Visit the Infobahn Offramp: <http://mcpierce.multiply.com>
"Bury me next to my wife. Nothing too fancy..." - Ulysses S. Grant

In the headers of every email you receive is:

List-Unsubscribe: <mailto:ruby-talk-ctl@ruby-lang.org?body=unsubscribe>

Try that. Or, alternatively, go to Google groups & unsubscribe there.

Cheers,

  Phil...

- --
But masters, remember that I am an ass.
Though it be not written down,
yet forget not that I am an ass.

  Wm. Shakespeare - Much Ado About Nothing

···

On 23/04/2012 16:37, Ender Ahmet Yurt wrote:

no one knows how we can do it. (:

On Mon, Apr 23, 2012 at 6:29 PM, Billy Alcazar <lists@ruby-forum.com > <mailto:lists@ruby-forum.com>> wrote:

    Please can some one show me how to stop getting emails from
    list@ruby-forum.com <mailto:list@ruby-forum.com>

This is my ((slightly?) horrible) workaround:

data = File.read(__FILE__).split(/__END__/).last

···

On Apr 23, 2012, at 04:49 , Wybo Dekker wrote:

That's clear, but does that mean there's no workaround?
Can Ruby not be told that the DATA section is somewhere else?

BEGIN {

      require 'stringio'
      DATA = StringIO.new(<<EOS)
      ...
      EOS
    }

Ah, the (unquoted) indentation is wrong in that heredoc, but you see the
idea.

···

On Mon, Apr 23, 2012 at 3:55 PM, Xavier Noria <fxn@hashref.com> wrote:

Ryan Davis писал 23.04.2012 22:58:

···

On Apr 23, 2012, at 04:49 , Wybo Dekker wrote:

That's clear, but does that mean there's no workaround?
Can Ruby not be told that the DATA section is somewhere else?

This is my ((slightly?) horrible) workaround:

data = File.read(__FILE__).split(/__END__/).last

This is better:
data = File.read(__FILE__).split(/__END__/, 2).last

1.9.3p125 :001 > "a,b,c".split(",", 2)
  => ["a", "b,c"]
1.9.3p125 :002 > "a,b,c".split(",")
  => ["a", "b", "c"]

--
   WBR, Peter Zotov.

That's great, thanks Peter, Ryan.
But it needs a correction, because the script is now also split on the
__END__ in the "data =..." line itself, so it needs a ^:

data = File.read(__FILE__).split(/^__END__/, 2).last

And Ryan's ,2 can be skipped if one wants more than one subsection in
the DATA section. Here's my test script, including the idea of using it
for erb templates:

#!/usr/bin/env ruby
require 'optparse'
require 'erb'

name = 'Unknown'
OptionParser.new do |opt|
    opt.on('-n','--name=STRING',String,
               'set the name'
          ) do |v| name = v end
end.parse!
data1,data2 = File.read(__FILE__).
                   split(/^__END__/)[1..-1].
                   map { |x| ERB.new(x).result(binding) }
puts '',"data1: #{data1}", '',"data2: #{data2}"
__END__
Hello <%= name %>
This is data 1, two lines.
__END__
This is data 2,
3 lines,
including this one.

···

On 2012-04-23 22:57, Peter Zotov wrote:

Ryan Davis писал 23.04.2012 22:58:

On Apr 23, 2012, at 04:49 , Wybo Dekker wrote:

That's clear, but does that mean there's no workaround?
Can Ruby not be told that the DATA section is somewhere else?

This is my ((slightly?) horrible) workaround:

data = File.read(__FILE__).split(/__END__/).last

This is better:
data = File.read(__FILE__).split(/__END__/, 2).last

--
Wybo

I you don't need the BEGIN block nor constants, I think you could just use some ordirary heredocs or some other conventional Ruby idiom.

···

Sent from my iPhone

On 24/04/2012, at 10:39, Wybo Dekker <wybo@xs4all.nl> wrote:

On 2012-04-23 22:57, Peter Zotov wrote:

Ryan Davis писал 23.04.2012 22:58:

On Apr 23, 2012, at 04:49 , Wybo Dekker wrote:

That's clear, but does that mean there's no workaround?
Can Ruby not be told that the DATA section is somewhere else?

This is my ((slightly?) horrible) workaround:

data = File.read(__FILE__).split(/__END__/).last

This is better:
data = File.read(__FILE__).split(/__END__/, 2).last

That's great, thanks Peter, Ryan.
But it needs a correction, because the script is now also split on the
__END__ in the "data =..." line itself, so it needs a ^:

data = File.read(__FILE__).split(/^__END__/, 2).last

And Ryan's ,2 can be skipped if one wants more than one subsection in
the DATA section. Here's my test script, including the idea of using it
for erb templates:

#!/usr/bin/env ruby
require 'optparse'
require 'erb'

name = 'Unknown'
OptionParser.new do |opt|
   opt.on('-n','--name=STRING',String,
              'set the name'
         ) do |v| name = v end
end.parse!
data1,data2 = File.read(__FILE__).
                  split(/^__END__/)[1..-1].
                  map { |x| ERB.new(x).result(binding) }
puts '',"data1: #{data1}", '',"data2: #{data2}"
__END__
Hello <%= name %>
This is data 1, two lines.
__END__
This is data 2,
3 lines,
including this one.

--
Wybo

sure, but as said in my initial mail, it's not very elegant to clog a
script with large blocks of erb templates...

···

On 2012-04-24 10:53, Xavier Noria wrote:

I you don't need the BEGIN block nor constants, I think you could just use some ordirary heredocs or some other conventional Ruby idiom.

--
Wybo

I agree to Xavier, it's not such a big difference. Just do

# single quotes are important!
MY_DATA = <<'DAT'
doc is here
DAT

And if you place it at the end of the script you have pretty much the
same as with __END__ - plus, you can even define more documents that
way. You could also do

MY_DATA = %q{
doc is here
}

MY_DATA = %q[
doc is here
]

etc.

Kind regards

robert

···

On Tue, Apr 24, 2012 at 11:01 AM, Wybo Dekker <wybo@xs4all.nl> wrote:

On 2012-04-24 10:53, Xavier Noria wrote:

I you don't need the BEGIN block nor constants, I think you could just use some ordirary heredocs or some other conventional Ruby idiom.

sure, but as said in my initial mail, it's not very elegant to clog a
script with large blocks of erb templates...

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

Maybe I don't see the clue, but putting the doc at the end of the script
(and thus necessarily using it before its definition) results in:

uninitialized constant MY_DATA (NameError)

···

On 2012-04-24 11:08, Robert Klemme wrote:

# single quotes are important!
MY_DATA = <<'DAT'
doc is here
DAT

And if you place it at the end of the script you have pretty much the
same as with __END__ - plus, you can even define more documents that
way. You could also do

--
Wybo

Putting it at the end does not necessarily mean you use it before the
definition especially if the file is a library file (i.e. no code gets
executed).

$ ruby19 y.rb
3

$ cat -n y.rb
     1
     2
     3 require './x'
     4
     5 puts size()
     6

$ cat -n x.rb
     1
     2
     3 def size
     4 return MY_DATA.length
     5 end
     6
     7
     8 MY_DATA = "foo"
     9

I cannot judge your case since your demo gem just contained demo
content. If you insist on having the data at the end, there are other
approaches as well:

$ ruby19 -r ./z.rb -e 'p get'
"This is\nmy\n\ndata\n"

rklemme@padrklemme2 /tmp/tmpenv.sh-8oDIBS
$ cat -n z.rb
     1
     2
     3 def get
     4 File.read(__FILE__)[%r{^=begi\s*#\s*DATA$\r?\n(.*)^=end\s*\z}m, 1]
     5 end
     6
     7 =begin # DATA
     8 This is
     9 my
    10
    11 data
    12 =end

Kind regards

rober

···

On Tue, Apr 24, 2012 at 2:59 PM, Wybo Dekker <wybo@xs4all.nl> wrote:

On 2012-04-24 11:08, Robert Klemme wrote:

# single quotes are important!
MY_DATA = <<'DAT'
doc is here
DAT

And if you place it at the end of the script you have pretty much the
same as with __END__ - plus, you can even define more documents that
way. You could also do

Maybe I don't see the clue, but putting the doc at the end of the script
(and thus necessarily using it before its definition) results in:

uninitialized constant MY_DATA (NameError)

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

Did you receive my reply (I think it was the first one in the thread?) with
the BEGIN blocks? Do you know what is a BEGIN block?

···

On Tue, Apr 24, 2012 at 2:59 PM, Wybo Dekker <wybo@xs4all.nl> wrote:

On 2012-04-24 11:08, Robert Klemme wrote:
> # single quotes are important!
> MY_DATA = <<'DAT'
> doc is here
> DAT
>
> And if you place it at the end of the script you have pretty much the
> same as with __END__ - plus, you can even define more documents that
> way. You could also do

Maybe I don't see the clue, but putting the doc at the end of the script
(and thus necessarily using it before its definition) results in:

uninitialized constant MY_DATA (NameError)

yes, but I didn't well understand it - now I see what you meant:

#!/usr/bin/env ruby
require 'optparse'

name = 'Unknown'
OptionParser.new do |opt|
    opt.on('-n','--name=STRING',String,
               'set the name'
          ) do |v| name = v end
end.parse!
puts '',"data1: #{DATA1.result(binding)}",
     '',"data2: #{DATA2.result(binding)}"

# __TEMPLATES__
BEGIN {
  require 'erb'
  DATA1 = ERB.new(<<-'DAT')
  Hello <%= name %>
  This is data 1, two lines.
  DAT

  DATA2 = ERB.new(<<-'DAT')
  This is data 2,
  3 lines,
  including this one.
  DAT
}

···

On 2012-04-24 15:28, Xavier Noria wrote:

Did you receive my reply (I think it was the first one in the thread?)
with the BEGIN blocks? Do you know what is a BEGIN block?

--
Wybo

Exactly! Given that __END__ is not per file, I think that solution is a
good compromise. It allows you to put this auxiliary stuff down the script,
and at the same time have it available in the main code.

One could invert the order and put the templates first, but I understand
your desire to put them down. That is, if __END__ was per file, we'd use it
for this case.