Created
August 22, 2010 20:19
-
-
Save ashmoran/544233 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # Yet another version with suggestions from workmad3 :-) | |
| # This time, pass in the keyword args into the block. | |
| # This means duplicating the definition of valid params, but | |
| # also means you get normal local variables in the method body. | |
| module DefK | |
| # NOTE: params is for syntactic sugar, and has no bearing on the | |
| # number of arguments you can call | |
| def def_k(method_name, *params, kparams, &method_body) | |
| define_method method_name do |*args| | |
| kargs = | |
| if args.last.is_a?(Hash) | |
| kparams.merge(args.delete_at(-1)) | |
| else | |
| kparams | |
| end | |
| args.concat(kargs.values) | |
| method_body.call(*args) | |
| end | |
| end | |
| end | |
| class Class | |
| include DefK | |
| end | |
| class Duck | |
| def_k :quack, name: "Donald" do |name| | |
| "QUACK #{name}" | |
| end | |
| end | |
| class Book | |
| class << self | |
| def_k :find, :selector, conditions: "", joins: [ ] do |selector, conditions, joins| | |
| sql = ["SELECT * FROM books"] | |
| joins.each do |join_table| | |
| sql << "LEFT OUTER JOIN #{join_table} ON" | |
| sql << "books.#{join_table.to_s.chop}_id" | |
| sql << "= #{join_table}.id" | |
| end | |
| sql << "WHERE #{conditions}" unless conditions.empty? | |
| sql << "LIMIT 1" if selector == :first | |
| sql.join(" ") + ";" | |
| end | |
| end | |
| end | |
| describe Duck do | |
| let(:duck) { Duck.new } | |
| describe "#quack" do | |
| it "quacks like Donald" do | |
| duck.quack.should eq "QUACK Donald" | |
| end | |
| it "quacks like Daffy" do | |
| duck.quack(name: "Daffy").should eq "QUACK Daffy" | |
| end | |
| end | |
| end | |
| describe Book do | |
| describe "#find" do | |
| it "supports :all" do | |
| Book.find(:all).should eq "SELECT * FROM books;" | |
| end | |
| it "supports :first" do | |
| Book.find(:first).should eq "SELECT * FROM books LIMIT 1;" | |
| end | |
| it "supports conditions" do | |
| Book.find(:all, conditions: "name = 'Animal Farm'").should eq "SELECT * FROM books WHERE name = 'Animal Farm';" | |
| end | |
| it "supports joins" do | |
| Book.find(:all, joins: %w[ authors publishers ]).should eq( | |
| "SELECT * FROM books " + | |
| "LEFT OUTER JOIN authors ON books.author_id = authors.id " + | |
| "LEFT OUTER JOIN publishers ON books.publisher_id = publishers.id;" | |
| ) | |
| end | |
| end | |
| end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # This version with workmad3's OpenStruct suggestion | |
| require 'ostruct' | |
| module DefK | |
| # NOTE: params is for syntactic sugar, and has no bearing on the | |
| # number of arguments you can call | |
| def def_k(method_name, *params, kparams, &method_body) | |
| define_method method_name do |*args| | |
| if args.last.is_a?(Hash) | |
| args[-1] = kparams.merge(args.last) | |
| else | |
| args << kparams | |
| end | |
| args[-1] = OpenStruct.new(args[-1]) | |
| method_body.call(*args) | |
| end | |
| end | |
| end | |
| class Class | |
| include DefK | |
| end | |
| class Duck | |
| def_k :quack, name: "Donald" do |kargs| | |
| "QUACK #{kargs.name}" | |
| end | |
| end | |
| class Book | |
| class << self | |
| def_k :find, :selector, conditions: "", joins: [ ] do |selector, kargs| | |
| sql = ["SELECT * FROM books"] | |
| kargs.joins.each do |join_table| | |
| sql << "LEFT OUTER JOIN #{join_table} ON" | |
| sql << "books.#{join_table.to_s.chop}_id" | |
| sql << "= #{join_table}.id" | |
| end | |
| sql << "WHERE #{kargs.conditions}" unless kargs.conditions.empty? | |
| sql << "LIMIT 1" if selector == :first | |
| sql.join(" ") + ";" | |
| end | |
| end | |
| end | |
| describe Duck do | |
| let(:duck) { Duck.new } | |
| describe "#quack" do | |
| it "quacks like Donald" do | |
| duck.quack.should eq "QUACK Donald" | |
| end | |
| it "quacks like Daffy" do | |
| duck.quack(name: "Daffy").should eq "QUACK Daffy" | |
| end | |
| end | |
| end | |
| describe Book do | |
| describe "#find" do | |
| it "supports :all" do | |
| Book.find(:all).should eq "SELECT * FROM books;" | |
| end | |
| it "supports :first" do | |
| Book.find(:first).should eq "SELECT * FROM books LIMIT 1;" | |
| end | |
| it "supports conditions" do | |
| Book.find(:all, conditions: "name = 'Animal Farm'").should eq "SELECT * FROM books WHERE name = 'Animal Farm';" | |
| end | |
| it "supports joins" do | |
| Book.find(:all, joins: %w[ authors publishers ]).should eq( | |
| "SELECT * FROM books " + | |
| "LEFT OUTER JOIN authors ON books.author_id = authors.id " + | |
| "LEFT OUTER JOIN publishers ON books.publisher_id = publishers.id;" | |
| ) | |
| end | |
| end | |
| end |
Author
That's the first thing I though of after hours of staring at args[-1]. It's only a code spike, there are loads of defects in the snippets above. I just wanted to see if the concept had any legs (it does, but it's limping at the moment...).
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Why use args.delete_at(-1) when you can use args.pop?