[nuby] shell-like substitution in a string

L

Lionel Thiry

Hi!

I'd like to make some kind of substitution like in a shell, i.e. having:
"${tool} -o ${target} -L${libpath} -l${lib} ${source}"

with an env like this:
env = {
"tool" => "gcc",
"target" => "hello.exe",
"libpath" => "/usr/lib",
"lib" => "somelib",
"source" => "hello.c"
}

it should give:
"gcc -o hello.exe -L/usr/lib -lsomelib hello.c"


It is easy until I want to manage caracter escapement like
"${var\\}weird}" which should give env["var}weird"], "\\${var}" which
should give the simple string "${var}" and "\\\\${var}" which should be
equivalent to "\\" + env["var"].

Any idea of how I could manage that?



Lionel Thiry
 
E

Eivind Eklund

Hi!

I'd like to make some kind of substitution like in a shell, i.e. having:
"${tool} -o ${target} -L${libpath} -l${lib} ${source}"

What's the full context of this?

In Ruby, you can interpolate into strings using "the #{code} part will
be replaced with whatever 'code' returns", so "5*5 is #{5*5}" becomes
"5*5 is 25".

However, because I don't really know your context, I don't know if
this can solve your problem. If it can't, please give more contextual
details.

Eivind.
 
A

Ara.T.Howard

Hi!

I'd like to make some kind of substitution like in a shell, i.e. having:
"${tool} -o ${target} -L${libpath} -l${lib} ${source}"

with an env like this:
env = {
"tool" => "gcc",
"target" => "hello.exe",
"libpath" => "/usr/lib",
"lib" => "somelib",
"source" => "hello.c"
}

it should give:
"gcc -o hello.exe -L/usr/lib -lsomelib hello.c"


It is easy until I want to manage caracter escapement like
"${var\\}weird}" which should give env["var}weird"], "\\${var}" which
should give the simple string "${var}" and "\\\\${var}" which should be
equivalent to "\\" + env["var"].

i don't think you need to worry about that since 'var}weird' is not a valid
shell identifier - at least i can't seem to create a var by that name in the
shell...
Any idea of how I could manage that?

you can get bash's exact parameter expansion like this:

jib:~ > cat a.rb
require 'session'

class Expander
def self::new(*a, &b)
@instance = super
end
def initialize
@bash = Session::Bash::new
end
def expand expr, context = {}
context.each do |k,v|
o, e = @bash.execute "#{ k }=#{ v }"
raise e unless e.empty?
end
stdout, stderr = @bash.execute "cat <<eos\n#{ expr }\neos"
raise stderr unless stderr.empty?
context.each{|k,v| @bash.execute "unset #{ k }"}
stdout.chomp
end
end

ex = Expander::new

expr = "${tool} -o ${target} -L${libpath} -l${lib} ${source}"

env = {
"tool" => "gcc",
"target" => "hello.exe",
"libpath" => "/usr/lib",
"lib" => "somelib",
"source" => "hello.c"
}

cmd = ex.expand expr, env
p cmd


jib:~ > ruby a.rb
"gcc -o hello.exe -L/usr/lib -lsomelib hello.c"


-a
--
===============================================================================
| EMAIL :: Ara [dot] T [dot] Howard [at] noaa [dot] gov
| PHONE :: 303.497.6469
| When you do something, you should burn yourself completely, like a good
| bonfire, leaving no trace of yourself. --Shunryu Suzuki
===============================================================================
 
K

Kaspar Schiess

--------------080202040905030102040008
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 7bit

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Hello Lionel,

That was quite a quiz you asked us ;)

I have a solution using only 'regular' regular expressions, the one in
1.8.1. Thus: this solution works without oniguruma.

I work around the lookbehind trouble by appending three spaces in front
of the string.

I am sure this solution is hideously complicated and can be improoved.
Anyone ?

Here's the output:
~ bluna ${var\}weird}
~ bluna weird substitute

~ sh ${tool} -o ${target} -L${libpath} -l${lib} ${source}
~ sh gcc -o test.exe -L/usr/lib -lopengl render.c

~ \${var}
~ \${var}

~ \\${var}
~ \\rvar

~ $\${var}
~ $\${var}

~ $\$${var}
~ $\$rvar

with an env of

~ env = {
'var\}weird' => 'weird substitute',
'var' => 'rvar',
'tool' => 'gcc',
'target' => 'test.exe',
'libpath' => '/usr/lib',
'lib' => 'opengl',
'source' => 'render.c'
~ }

Hope this hits your nerv,
kaspar
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.4 (MingW32)
Comment: Using GnuPG with Thunderbird - http://enigmail.mozdev.org

iD8DBQFBbmnPFifl4CA0ImQRAjF/AJ4oweuSNuxknxcslsv0f3S9GFiebACfXO7B
GYygYzZW0Co4z5S2na7y5Os=
=wcON
-----END PGP SIGNATURE-----

--------------080202040905030102040008
Content-Type: text/plain;
name="interpolation.rb"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
filename="interpolation.rb"

tests = []

tests << 'bluna ${var\\}weird}'
tests << 'sh ${tool} -o ${target} -L${libpath} -l${lib} ${source}'
tests << '\\${var}'
tests << '\\\\${var}'
tests << '$\${var}'
tests << '$\$${var}'


env = {
'var\}weird' => 'weird substitute',
'var' => 'rvar',
'tool' => 'gcc',
'target' => 'test.exe',
'libpath' => '/usr/lib',
'lib' => 'opengl',
'source' => 'render.c'
}

class ShellExpander
REString = /
^
(?:
\\ . |
[^\\$] |
\$ \\ . |
\$ [^\\{]
){3,}
\$ \{
(
(?: \\ . | [^\\}] )*
)
}
/x

def initialize env={}
@env = env
end

# call-seq:
# #expand( str ) => str
def expand str
for_each_shell_expansion_in str do |var|
@env[var]
end
end

def for_each_shell_expansion_in str
tomatch = str
replacements = []
offset = 0
while str.length > 0
tomatch = ' '*3 + tomatch
offset -= 3
md = REString.match tomatch
break unless md

replacement = yield( md[1] )
i, j = offset+md.begin(1), offset+md.end(1)

replacements << [i, j, replacement] if replacement

offset += md.pre_match.length + md[0].length
tomatch = md.post_match
end

offset = 0
replacements.each do |from, to, rep|
str[ (offset+from-2)...(offset+to+1) ] = rep

offset += rep.length - (to-from+3)
end

str
end
end

expander = ShellExpander.new env

tests.each do |str|
puts
puts str
puts expander.expand(str)
end



--------------080202040905030102040008--
 
L

Lionel Thiry

(e-mail address removed) a écrit :
Hi!

I'd like to make some kind of substitution like in a shell, i.e. having:
"${tool} -o ${target} -L${libpath} -l${lib} ${source}"

with an env like this:
env = {
"tool" => "gcc",
"target" => "hello.exe",
"libpath" => "/usr/lib",
"lib" => "somelib",
"source" => "hello.c"
}

it should give:
"gcc -o hello.exe -L/usr/lib -lsomelib hello.c"


It is easy until I want to manage caracter escapement like
"${var\\}weird}" which should give env["var}weird"], "\\${var}" which
should give the simple string "${var}" and "\\\\${var}" which should be
equivalent to "\\" + env["var"].


i don't think you need to worry about that since 'var}weird' is not a valid
shell identifier - at least i can't seem to create a var by that name in
the
shell...
Pertinent remark, noted.
you can get bash's exact parameter expansion like this:

jib:~ > cat a.rb
require 'session'
I'm working on win2k with on-click installer ruby v1.8.1-13 and
unfortunately, there is no session file that can be required.

Lionel Thiry
 
L

Lionel Thiry

Hello!

Thanks for the help, but I can already handle the recursive expansion of
the strings. My main problem is about the pattern itself, it gives me
headaches.

Some comments follow.

Kaspar Schiess a écrit :
Hello Lionel,

That was quite a quiz you asked us ;)

I have a solution using only 'regular' regular expressions, the one in
1.8.1. Thus: this solution works without oniguruma.

I work around the lookbehind trouble by appending three spaces in front
of the string.

I am sure this solution is hideously complicated and can be improoved.
Anyone ?

Here's the output:
~ bluna ${var\}weird}
~ bluna weird substitute

~ sh ${tool} -o ${target} -L${libpath} -l${lib} ${source}
~ sh gcc -o test.exe -L/usr/lib -lopengl render.c

~ \${var}
~ \${var}
I'd prefer '${var}' as a result, is it possible? Doesn't the (?>re)
expression fit for that purpose? Or should I make some substitution
after the match?
~ \\${var}
~ \\rvar

~ $\${var}
~ $\${var}
In fact, this case should generate an exception, as a non escaped $
should always be immediately followed by a {.
~ $\$${var}
~ $\$rvar
Idem.
But "\\$${var}" should give "$rvar", ideal for letting the shell to make
some postsubstitution with its usual env.
with an env of

~ env = {
'var\}weird' => 'weird substitute',
'var' => 'rvar',
'tool' => 'gcc',
'target' => 'test.exe',
'libpath' => '/usr/lib',
'lib' => 'opengl',
'source' => 'render.c'
~ }

Hope this hits your nerv,
kaspar
I still have a lot of work, but thanks for the help.

Lionel Thiry
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,756
Messages
2,569,540
Members
45,025
Latest member
KetoRushACVFitness

Latest Threads

Top