Binding scope

Hi,

I’m trying to implement a simple parser and quite likely going about it
the wrong way.

I would like to be able to include a bit of ruby code in a string, which
is saved to a field in a database. When the string is retrieve from the
database at a later stage, I want to parse it for code and evaluate the
code, substituting the result value into the string.

I’ve been trying to do something like this:

module Substitutable
@other_word = “other word”
proc = Proc.new{}
String.class_eval do
define_method :to_s do
self.gsub(/(.?)</code>/) do |match|
code = match.scan(/(.
)</code>/).flatten.first
eval(code, proc.binding)
end
end
end
end

If I then create a class and include Substitutable, I get the

following output

class Tester

include Substitutable

def say
@word = “hello”
@other_word’.to_s # => “other word”
@word’.to_s # => “”
“hard coded word”’.to_s # => “hard coded word”
end
end

Tester.new.say

So I know that conceptually passing the a proc to the eval method does
enable me to set an instance variable out of the scope of the new to_s
method. But I cannot work out how to get the scope of the class within
which Substitutable has been "include"d. I’ve tried various things
like…

a) creating an “proc” method within the class that returns a proc object
b) creating a “@proc” instance variable within the class

…but with no luck.

Is what I’m trying to do possible?

Thanks very much in advance…

Dave

Hi,

Thought I’d try one poke to see if I could resurrect this. I’m still
stumped on how to solve this.

Thanks in advance.

Regards,
Dave

Dave B. wrote:

Hi,

I’m trying to implement a simple parser and quite likely going about it
the wrong way.

I would like to be able to include a bit of ruby code in a string, which
is saved to a field in a database. When the string is retrieve from the
database at a later stage, I want to parse it for code and evaluate the
code, substituting the result value into the string.

You are aware of the serious security problems with this, right?

[…]

But I cannot work out how to get the scope of the class within
which Substitutable has been "include"d.

Perhaps you should use the Module#included callback to register it.

Best,
–Â
Marnen Laibow-Koser
http://www.marnen.org
[email protected]

Hi Marnen

Thanks very much for the reponse.

Marnen Laibow-Koser wrote:

Dave B. wrote:

You are aware of the serious security problems with this, right?

Yes, this isn’t a public-facing site, and there will be no front-end
access to the database that will generate and store the code.

[…]

But I cannot work out how to get the scope of the class within
which Substitutable has been "include"d.

Perhaps you should use the Module#included callback to register it.

I will look at this - thanks again for the tip.

Regards,
Dave

Best,
–Â
Marnen Laibow-Koser
http://www.marnen.org
[email protected]

Marnen Laibow-Koser wrote:

Dave B. wrote:

Hi Marnen

Thanks very much for the reponse.

Marnen Laibow-Koser wrote:

Dave B. wrote:

You are aware of the serious security problems with this, right?

Yes, this isn’t a public-facing site, and there will be no front-end
access to the database that will generate and store the code.

Then you shouldn’t need to do this in the first place. If there’s no
frontend access to the DB, presumably that means that the app itself is
generating the code. If so, then it can keep it as a method in a live
object rather than writing it to the database and opening up a security
hole.

To give you a bit of background to this - I’ve got a “macro” that is
generating a bunch of reports. The reports contain lines like “the
number of people in this group are X and they have spent a total of Y on
your product this year”. The problem is, I can’t substitute X and Y for
their real values at the time the macro runs, because I don’t know what
filters the user will apply when viewing the reports. So I need a way
to do the calculations and substitute in the values when the user views
the report, and to recalculate these each time the user changes the
filter (e.g. show me only people older than 30).

So unless I’m missing something, I can’t keep a live object.

It’s a rails app, and the controller will be pulling together a
@results” variable, but will not necessarily know what kinds of stats
need to be pulled from it. That’s why i’d like to be able to do things
like “the number of people in this group are @results.size
and they spent @results.collect(&:spend).sum on your
product this year”.

Doees this make sense?

[…]

But I cannot work out how to get the scope of the class within
which Substitutable has been "include"d.

Perhaps you should use the Module#included callback to register it.

I will look at this - thanks again for the tip.

Regards,
Dave

Best,
–Â
Marnen Laibow-Koser
http://www.marnen.org
[email protected]

Best,
–Â
Marnen Laibow-Koser
http://www.marnen.org
[email protected]

On 2010-01-15, Dave B. [email protected] wrote:

To give you a bit of background to this - I’ve got a “macro” that is
generating a bunch of reports. The reports contain lines like “the
number of people in this group are X and they have spent a total of Y on
your product this year”. The problem is, I can’t substitute X and Y for
their real values at the time the macro runs, because I don’t know what
filters the user will apply when viewing the reports. So I need a way
to do the calculations and substitute in the values when the user views
the report, and to recalculate these each time the user changes the
filter (e.g. show me only people older than 30).

Check with a rails group, but I’m pretty sure you’ll find that you can,
in fact, do this natively in rails without the security hole.

-s

Dave B. wrote:

Hi Marnen

Thanks very much for the reponse.

Marnen Laibow-Koser wrote:

Dave B. wrote:

You are aware of the serious security problems with this, right?

Yes, this isn’t a public-facing site, and there will be no front-end
access to the database that will generate and store the code.

Then you shouldn’t need to do this in the first place. If there’s no
frontend access to the DB, presumably that means that the app itself is
generating the code. If so, then it can keep it as a method in a live
object rather than writing it to the database and opening up a security
hole.

[…]

But I cannot work out how to get the scope of the class within
which Substitutable has been "include"d.

Perhaps you should use the Module#included callback to register it.

I will look at this - thanks again for the tip.

Regards,
Dave

Best,
–Â
Marnen Laibow-Koser
http://www.marnen.org
[email protected]

Best,
–Â
Marnen Laibow-Koser
http://www.marnen.org
[email protected]

On Fri, Jan 15, 2010 at 8:42 AM, Dave B. [email protected]
wrote:

So unless I’m missing something, I can’t keep a live object.

It’s a rails app, and the controller will be pulling together a
@results” variable, but will not necessarily know what kinds of stats
need to be pulled from it. That’s why i’d like to be able to do things
like “the number of people in this group are @results.size
and they spent @results.collect(&:spend).sum on your
product this year”.

I don’t really see the benefit of storing the template in the database,
but
here is what I came up with.

require ‘rubygems’
require ‘activerecord’
require ‘sqlite3’
require ‘erb’

documentation at http://www.sqlite.org/lang_createtable.html

db = SQLite3::Database.new( ‘store_and_execute_strings.db’ )
db.execute <<-__________________________________________________
CREATE TABLE IF NOT EXISTS reports (
id INTEGER PRIMARY KEY ASC AUTOINCREMENT,
title Text,
template TEXT
);
__________________________________________________

db.execute <<-__________________________________________________
CREATE TABLE IF NOT EXISTS groups (
id INTEGER PRIMARY KEY ASC AUTOINCREMENT,
name STRING
);
__________________________________________________

db.execute <<-__________________________________________________
CREATE TABLE IF NOT EXISTS people (
id INTEGER PRIMARY KEY ASC AUTOINCREMENT,
group_id INTEGER,
money_spent DOUBLE,
age INTEGER
);
__________________________________________________

documentation at

for other (better, depending on your needs) documentation, see

http://guides.rubyonrails.org/activerecord_validations_callbacks.html
ActiveRecord::Base.establish_connection :adapter =>
‘sqlite3’ ,
:host =>
‘localhost’ ,
:database =>
‘store_and_execute_strings.db’ ,
:username =>
‘root’ ,
:password => ‘’

class Report < ActiveRecord::Base
def generate( &init )
dup.instance_eval {
instance_eval &init if init
ERB.new( template , 0 , “%<>” ).result( binding )
}
end
end

class Group < ActiveRecord::Base
has_many :people
end

class Person < ActiveRecord::Base
belongs_to :group
end

here is an example, as I understand your criteria

text_for_report = "the number of people in this group are <%=
@people.length
%> and they have spent "
"a total of $<%= @people.inject(0) { |sum,person|
sum+person.money_spent.to_f } %> "
“on your product this year”

Report.new( :template => text_for_report , :title => ‘Customer Summary’
).save

doctors = Group.new :name => ‘doctors’
doctors.save

(1…10).each do |num|
money , age = num , 20+num*5
doctors.people.build( :money_spent => money , :age => age ).save
end

customer_summary = Report.find_by_title ‘Customer Summary’

puts customer_summary.generate { @people =
doctors.people }
puts customer_summary.generate { @people = doctors.people.all
:conditions =>
‘money_spent <= 5’ }
puts customer_summary.generate { @people = doctors.people.all
:conditions =>
‘age < 40’ }

Josh, thanks VERY much for the response. I’m going to digest it and
will let you know once I’ve got it working.

Have a good weekend.

Cheers,
Dave

Josh C. wrote:

Hmm, formatting looks really bad up on my email, here is a pastie for it
http://pastie.org/private/taieshtr0nwhnv1unkrjq

Hmm, formatting looks really bad up on my email, here is a pastie for it
http://pastie.org/private/taieshtr0nwhnv1unkrjq

Dave B. wrote:

Josh, thanks VERY much for the response. I’m going to digest it and
will let you know once I’ve got it working

No. Better to go for a solution without the security hole. It should be
possible, but ask on the Rails list instead.

Have a good weekend.

Cheers,
Dave

Josh C. wrote:

Hmm, formatting looks really bad up on my email, here is a pastie for it
http://pastie.org/private/taieshtr0nwhnv1unkrjq

Best,
–Â
Marnen Laibow-Koser
http://www.marnen.org
[email protected]