From: Yehuda Katz Date: 2008-12-03T04:06:11+09:00 Subject: [ruby-core:20221] Re: Proposal: deferred blocks ------=_Part_80229_29613502.1228245108855 Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit Content-Disposition: inline My example was only a real-use that already exists. You articulated the problems with your approach (namely, it falls apart when you hit language constructs). People have been playing with this for a while, but a big blocker is the fact that it's known not to work outside of 1.8.x MRI. As I clarified earlier, I'm not asking for ParseTree functionality in Ruby. I'm asking for procs to optionally remember their string form so that they can be processed by other utilities (like RubyParser). It's not as intensive as requiring that Ruby have a standard AST across implementations, and might potentially have other benefits (error handling, for instance). -- Yehuda On Tue, Dec 2, 2008 at 10:47 AM, Florian Gilcher wrote: > -----BEGIN PGP SIGNED MESSAGE----- > Hash: SHA1 > > Hi Yehuda, > > Is this really necessary? > > I've been playing alot with instance_exec and and fake objects and have > been able to mimic at least such basic stuff without resorting to using the > parsetree.[1] You can get a long way with that, as long as you don't hit > true language constructs (|| and such). > > I still have my issues with parstree-hackery and don't see the point why we > desperatly need it - especially in core Ruby. Also, I don't see the point of > most examples for this, including yours. Ruby will never be SQL. If you want > to query in Ruby, use a language that takes Ruby-code as query language. > parsetree-hackery depends on a feature of the interpreter that is not at all > standardized. > > To show you an example how your specific problem can easily be solved with > more-than-plain Ruby is attached - it takes more work to bring it the whole > way. Be aware that you should use some kind of BlankSlate-Object for this, > but for example-reasons, I left it out. It also only cares about this really > specific example. > > Regards, > Florian Gilcher > > P.S.: If i see this in dm-core, i'll stop using DM. And that would be tough > for me. > > [1]: For those who saw my talk about Patterns on EuRuKo 2008: yes, for > this. Sadly, still unreleased. > > ==Code== > > class SelectProxy < BasicObject > attr_accessor :model, :queried_attribs > > def initialize(model) > @model = model > @queried_attribs = {} > end > > def method_missing(selector, *args) > if @model.attributes.include? selector > self.queried_attribs[selector] ||= ::AttributeProxy.new(selector) > end > > #if not, do something else > end > > #this is totally bad, but for the sake of an example... > def compile > tablename = @model.name.downcase > conditions = queried_attribs.values.map do |attribute| > attribute.queries.join(" AND ") > end.join(" AND ") > "SELECT * FROM #{tablename} WHERE #{conditions}" > end > end > > class AttributeProxy > attr_accessor :attribute, :queries > > def initialize(attribute) > @attribute = attribute > @queries = [] > end > > def =~(arg) > @queries << "#{self.attribute} ~ '#{arg.source}'" > end > > end > > class Article > #lets assume we can get a list of attributes on class level > class << self > attr_accessor :attributes > end > > self.attributes = [:title, :body] > > def self.select(&block) > proxy = SelectProxy.new(self) > proxy.instance_exec &block > return proxy.compile > end > end > > puts Article.select { title =~ /Some title/ } > > -----BEGIN PGP SIGNATURE----- > Version: GnuPG v1.4.8 (Darwin) > > iEYEARECAAYFAkk1g/kACgkQyLKU2FMxSOJWpwCgqauexnrTJ7UVK64YMxGz+1DE > 6gwAoIXkxut6H+TBGgX6FFhD/kb+hxSE > =fZIe > -----END PGP SIGNATURE----- > > -- Yehuda Katz Developer | Engine Yard (ph) 718.877.1325 ------=_Part_80229_29613502.1228245108855 Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit Content-Disposition: inline My example was only a real-use that already exists.

You articulated the problems with your approach (namely, it falls apart when you hit language constructs). People have been playing with this for a while, but a big blocker is the fact that it's known not to work outside of 1.8.x MRI.

As I clarified earlier, I'm not asking for ParseTree functionality in Ruby. I'm asking for procs to optionally remember their string form so that they can be processed by other utilities (like RubyParser). It's not as intensive as requiring that Ruby have a standard AST across implementations, and might potentially have other benefits (error handling, for instance).

-- Yehuda

On Tue, Dec 2, 2008 at 10:47 AM, Florian Gilcher <flo@andersground.net> wrote:
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Hi Yehuda,

Is this really necessary?

I've been playing alot with instance_exec and and fake objects and have been able to mimic at least such basic stuff without resorting to using the parsetree.[1] You can get a long way with that, as long as you don't hit true language constructs (|| and such).

I still have my issues with parstree-hackery and don't see the point why we desperatly need it - especially in core Ruby. Also, I don't see the point of most examples for this, including yours. Ruby will never be SQL. If you want to query in Ruby, use a language that takes Ruby-code as query language. parsetree-hackery depends on a feature of the interpreter that is not at all standardized.

To show you an example how your specific problem can easily be solved with more-than-plain Ruby is attached - it takes more work to bring it the whole way. Be aware that you should use some kind of BlankSlate-Object for this, but for example-reasons, I left it out. It also only cares about this really specific example.

Regards,
Florian Gilcher

P.S.: If i see this in dm-core, i'll stop using DM. And that would be tough for me.

[1]: For those who saw my talk about Patterns on EuRuKo 2008: yes, for this. Sadly, still unreleased.

==Code==

class SelectProxy < BasicObject
 attr_accessor :model, :queried_attribs

 def initialize(model)
  @model = model
  @queried_attribs = {}
 end

 def method_missing(selector, *args)
  if @model.attributes.include? selector
    self.queried_attribs[selector] ||= ::AttributeProxy.new(selector)
  end

  #if not, do something else
 end

 #this is totally bad, but for the sake of an example...
 def compile
  tablename = @model.name.downcase
  conditions = queried_attribs.values.map do |attribute|
                  attribute.queries.join(" AND ")
               end.join(" AND ")
  "SELECT * FROM #{tablename} WHERE #{conditions}"
 end
end

class AttributeProxy
 attr_accessor :attribute, :queries

 def initialize(attribute)
  @attribute = attribute
  @queries = []
 end

 def =~(arg)
  @queries << "#{self.attribute} ~ '#{arg.source}'"
 end

end

class Article
 #lets assume we can get a list of attributes on class level
 class << self
  attr_accessor :attributes
 end

 self.attributes = [:title, :body]

 def self.select(&block)
  proxy = SelectProxy.new(self)
  proxy.instance_exec &block
  return proxy.compile
 end
end

puts Article.select { title =~ /Some title/ }

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.8 (Darwin)

iEYEARECAAYFAkk1g/kACgkQyLKU2FMxSOJWpwCgqauexnrTJ7UVK64YMxGz+1DE
6gwAoIXkxut6H+TBGgX6FFhD/kb+hxSE
=fZIe
-----END PGP SIGNATURE-----




--
Yehuda Katz
Developer | Engine Yard
(ph) 718.877.1325
------=_Part_80229_29613502.1228245108855--