Passing Binding or Arguments to Erb from the Command Line

Passing binding or arguments to ERB from the command line

If you are using unix, try following:

$ cat 1.erb
Hello. My name is <%= name %>. I hope your day is <%= quality %>.
$ (echo '<% name="Joe"; quality="fantastic" %>' && cat 1.erb) | erb

Hello. My name is Joe. I hope your day is fantastic.

Can I pass variables to be rendered by erb from the command line?

As of Ruby 2.2 you can set local variables in Erb from the command line.

You would need to change your code to use local variables rather than instance variables. For example if you had (stripped down from your code):

<VirtualHost <%= http_host %>:<%= http_port %>>

You could then call it with:

$ erb http_host=http://example.com http_port=1234 my_file.erb

and the result would be:

<VirtualHost http://example.com:1234>

How to pass binding with ERB.result_with_hash

In your case, if you need to use both the args and binding, you need to populate keys/values of your args into the binding object.

# To avoid polluting your current binding, copy to a new one
b_clone = binding.clone
args.each { |k, v| b_clone.local_variable_set(k,v) }
ERB.new(template).result(b_clone)

So you can use both methods in your binding and keys/values in args as variables

Ruby templates: How to pass variables into inlined ERB?

Got it!

I create a bindings class

class BindMe
def initialize(key,val)
@key=key
@val=val
end
def get_binding
return binding()
end
end

and pass an instance to ERB

dataHash.keys.each do |current|
key = current.to_s
val = dataHash[key]

# here, I pass the bindings instance to ERB
bindMe = BindMe.new(key,val)

result = template.result(bindMe.get_binding)

# unnecessary code goes here
end

The .erb template file looks like this:

Key: <%= @key %>

How do I execute ruby template files (ERB) without a web server from command line?

You should have everything you need in your ruby/bin directory. On my (WinXP, Ruby 1.8.6) system, I have ruby/bin/erb.bat

erb.bat [switches] [inputfile]
-x print ruby script
-n print ruby script with line number
-v enable verbose mode
-d set $DEBUG to true
-r [library] load a library
-K [kcode] specify KANJI code-set
-S [safe_level] set $SAFE (0..4)
-T [trim_mode] specify trim_mode (0..2, -)
-P ignore lines which start with "%"

so erb your_erb_file.erb should write the result to STDOUT.

(EDIT: windows has erb.bat and just plain "erb". The .bat file is just a wrapper for erb, which I guess should make the same command work pretty much the same on any OS)

See the prag prog book discussion (starts about half-way down the page).

Note also that Jack Herrington wrote a whole book about code generation that uses Ruby/ERB.

how to use erb to output file after binding

Note that ERB isn't printing this - you are.

print erb.result( binding )

Let's change that. We'll open the file handle, in w mode to write, and write the ERB result to the file.

File.open('text2.txt', 'w') do |f|
f.write erb.result(binding)
end

File.open('text2.txt', 'w') opens the file text2.txt in write mode, and passes that file object into the block. f.write outputs its argument to the file. In some cases you might need to call f.close to allow other processes on your computer to access the file, but since we used the block notation here instead, the file is closed automatically at the end of the block.

Code untested - let me know if you get an error. Good luck on your coding journey!

Passing multiple pieces of data via command line to be separately evaluated using ARGV

If I properly understood what you want to do:

ARGV.each_slice(3) { |a1, a2, a3|
# NB: a2 and/or a3 may be nil here if ARGV.size % 3 ≠ 0
puts "#{a1}×#{a2}×#{a3}"
}
puts "Init NOW"

Yielding:

~ ruby a.rb arg1 arg2 arg3 arg4 arg5 arg6 arg7
# arg1×arg2×arg3
# arg4×arg5×arg6
# arg7××
# Init NOW

UPD
After a clarification of the task:

class Operator
attr_accessor :a1, :a2, :a3, :a4
def initialize attrs
@a1, @a2, @a3, @a4 = attrs
end
def begin
puts "[BEGIN] ⇒ 1: #{@a1}, 2: #{@a2}, 3: #{@a3}"
end
def add
puts "[ADD] ⇒ 1: #{@a1}, 2: #{@a2}, 3: #{@a3}, 4: #{@a4}"
end
def subtract
puts "[SUBTR] ⇒ 1: #{@a1}, 2: #{@a2}, 3: #{@a3}, 4: #{@a4}"
end
end

meth, *args = ARGV

Operator.new(args).send (meth.to_sym)

Which gives:

~ ruby a.rb add arg1 arg2 arg3 arg4
# [ADD] ⇒ 1: arg1, 2: arg2, 3: arg3, 4: arg4
~ ruby a.rb begin arg1 arg2 arg3
# [BEGIN] ⇒ 1: arg1, 2: arg2, 3: arg3

ERB partials to create static html with command line

What about this script:

require 'erb'

def render(filename)
ERB.new(File.read "#{filename}.html.erb").result(binding)
end

File.open('new-test.html', 'w') do |file|
file.write render('test')
end

It will read your test.html.erb, interpolate the ruby code properly including the calls to our custom render (so no need for any external library to handle that), and output a new-test.html file. You can run it by:

ruby script_name.rb

Notice how we need to provide a binding object to ERB. It is what defines the context of evaluation of the interpolated ruby in the template. Here we are providing the binding of the script itself, that's why we have access to the render method inside the erb template.

Ruby - Automatically pass binding() to method like eval?

Okay, so it turns out there's no easy answer. I've compiled a list here:

Ruby: Binding of Caller Solutions

And it breaks down to the following possibilities (expanded on in the link above):

  1. Use binding_of_caller gem
  2. Use a really sneaky pure ruby trick that only works if your method takes no args (involving define_singleton_method and then composing (>>) Object::method(:binding) with your method). See examples at https://bugs.ruby-lang.org/issues/18487
  3. Use TracePoint API for a pure ruby solution that is amazingly slow
  4. Call rb_eval_string_protect("binding") inside of a C extension which, until Ruby 3.2.0, will get you all of the binding (but with a corrupted receiver)
  5. Use my cut down C extension that takes the important bits out of the gem that binding_of_caller depends upon (debug_inspector)


Related Topics



Leave a reply



Submit