How can I write the awesome kind of code?

I'm writing a small app to do poker simulations. I read a lot of
blogs in which the author shows off his cool DSL. I decided I want to
be able to specify a poker hand in my app like

hand "my_hand" do
  players 10
  chips 1000
end

my_hand.foo

How can I do something like that?

Pat

class Hand
   ...
end

def hand( ..., &init )
   Hand.new( ... ).instance_eval(&init)
end

I really think you'll be happy in the long run though if you drop the instance_eval() and pass the hand into the block instead.

James Edward Gray II

···

On May 8, 2006, at 1:38 PM, Pat Maddox wrote:

I'm writing a small app to do poker simulations. I read a lot of
blogs in which the author shows off his cool DSL. I decided I want to
be able to specify a poker hand in my app like

hand "my_hand" do
players 10
chips 1000
end

my_hand.foo

How can I do something like that?

class Hand
   def initialize(name, &block)
       @name = name
       if block
          instance_eval(&block)
       end
       self
   end
   def players(i)
       @players = i
   end

   def chips(i)
       @chips = i
   end

   def foo
     puts self.inspect
   end
end

def hand(name, &block)
     Hand.new(name, &block)
end

my_hand = hand "my_hand" do
             players 10
             chips 1000
           end

my_hand.foo

#<Hand:0x363450 @name="my_hand", @chips=1000, @players=10>

If you want to automatically set 'my_hand' you can put it inside an enclosing object and dynamically define the my_hand method

···

On May 8, 2006, at 2:38 PM, Pat Maddox wrote:

I'm writing a small app to do poker simulations. I read a lot of
blogs in which the author shows off his cool DSL. I decided I want to
be able to specify a poker hand in my app like

hand "my_hand" do
players 10
chips 1000
end

my_hand.foo

How can I do something like that?

Pat

Okay so now I have

class Hand
  def players(p = nil)
    @players = p unless p.nil?
    @players
  end

  def chips(c = nil)
    @chips = c unless c.nil?
    @chips
  end
end

def hand(&init)
  yield(Hand.new) if block_given?
end

hand do |h|
  h.players 10
  h.chips 1000
end

Does that look right?

How can I use the Hand object that I just created?

···

On 5/8/06, James Edward Gray II <james@grayproductions.net> wrote:

On May 8, 2006, at 1:38 PM, Pat Maddox wrote:

> I'm writing a small app to do poker simulations. I read a lot of
> blogs in which the author shows off his cool DSL. I decided I want to
> be able to specify a poker hand in my app like
>
> hand "my_hand" do
> players 10
> chips 1000
> end
>
> my_hand.foo
>
> How can I do something like that?

class Hand
   ...
end

def hand( ..., &init )
   Hand.new( ... ).instance_eval(&init)
end

I really think you'll be happy in the long run though if you drop the
instance_eval() and pass the hand into the block instead.

James Edward Gray II

Hey Logan,

Thanks for the input. Here's what I ended up with. I don't know if
I'm doing bad stuff though to define the object - please let me know. In the hand method, I'm creating the hand and passing the block like
normally. Then to let me call the hand by the name I pass in, I
define a new method that calls a closure that simply returns the value
of the newly created object. It works great...I just don't know if
there's a better way, or if this is a bad approach.

class Hand
  def players(p = nil)
    @players = p unless p.nil?
    @players
  end

  def chips(c = nil)
    @chips = c unless c.nil?
    @chips
  end
end

def hand(name, &init)
  h = Hand.new
  yield(h) if block_given?
  self.class.class_eval { define_method(name) { proc { h }.call } }
  h
end

hand "my_hand" do |h|
  h.players 10
  h.chips 1000
end

puts my_hand.inspect

···

On 5/8/06, Logan Capaldo <logancapaldo@gmail.com> wrote:

On May 8, 2006, at 2:38 PM, Pat Maddox wrote:

> I'm writing a small app to do poker simulations. I read a lot of
> blogs in which the author shows off his cool DSL. I decided I want to
> be able to specify a poker hand in my app like
>
> hand "my_hand" do
> players 10
> chips 1000
> end
>
> my_hand.foo
>
> How can I do something like that?
>
> Pat
>

class Hand
   def initialize(name, &block)
       @name = name
       if block
          instance_eval(&block)
       end
       self
   end
   def players(i)
       @players = i
   end

   def chips(i)
       @chips = i
   end

   def foo
     puts self.inspect
   end
end

def hand(name, &block)
     Hand.new(name, &block)
end

my_hand = hand "my_hand" do
             players 10
             chips 1000
           end

my_hand.foo

#<Hand:0x363450 @name="my_hand", @chips=1000, @players=10>

If you want to automatically set 'my_hand' you can put it inside an
enclosing object and dynamically define the my_hand method

You can remove the &init parameter to hand(), since you are using yield. You may also want to make players() and chips() more Rubyish with players=() and chips=().

To keep the hand object you could have hand return it, or perhaps add it to some global Hash by name.

Hope that helps.

James Edward Gray II

···

On May 8, 2006, at 1:59 PM, Pat Maddox wrote:

On 5/8/06, James Edward Gray II <james@grayproductions.net> wrote:

On May 8, 2006, at 1:38 PM, Pat Maddox wrote:

> I'm writing a small app to do poker simulations. I read a lot of
> blogs in which the author shows off his cool DSL. I decided I want to
> be able to specify a poker hand in my app like
>
> hand "my_hand" do
> players 10
> chips 1000
> end
>
> my_hand.foo
>
> How can I do something like that?

class Hand
   ...
end

def hand( ..., &init )
   Hand.new( ... ).instance_eval(&init)
end

I really think you'll be happy in the long run though if you drop the
instance_eval() and pass the hand into the block instead.

James Edward Gray II

Okay so now I have

class Hand
def players(p = nil)
   @players = p unless p.nil?
   @players
end

def chips(c = nil)
   @chips = c unless c.nil?
   @chips
end
end

def hand(&init)
yield(Hand.new) if block_given?
end

hand do |h|
h.players 10
h.chips 1000
end

Does that look right?

proc { h }.call is redundant.

define_method(name) { h } should work

Though I question whether hand name { ... } is necessary.

Why not just do

my_hand = hand do |h|
             h.players 10
             h.chips 1000
end

puts my_hand.inspect

···

On May 8, 2006, at 3:13 PM, Pat Maddox wrote:

On 5/8/06, Logan Capaldo <logancapaldo@gmail.com> wrote:

On May 8, 2006, at 2:38 PM, Pat Maddox wrote:

> I'm writing a small app to do poker simulations. I read a lot of
> blogs in which the author shows off his cool DSL. I decided I want to
> be able to specify a poker hand in my app like
>
> hand "my_hand" do
> players 10
> chips 1000
> end
>
> my_hand.foo
>
> How can I do something like that?
>
> Pat
>

class Hand
   def initialize(name, &block)
       @name = name
       if block
          instance_eval(&block)
       end
       self
   end
   def players(i)
       @players = i
   end

   def chips(i)
       @chips = i
   end

   def foo
     puts self.inspect
   end
end

def hand(name, &block)
     Hand.new(name, &block)
end

my_hand = hand "my_hand" do
             players 10
             chips 1000
           end

my_hand.foo

#<Hand:0x363450 @name="my_hand", @chips=1000, @players=10>

If you want to automatically set 'my_hand' you can put it inside an
enclosing object and dynamically define the my_hand method

Hey Logan,

Thanks for the input. Here's what I ended up with. I don't know if
I'm doing bad stuff though to define the object - please let me know. In the hand method, I'm creating the hand and passing the block like
normally. Then to let me call the hand by the name I pass in, I
define a new method that calls a closure that simply returns the value
of the newly created object. It works great...I just don't know if
there's a better way, or if this is a bad approach.

class Hand
def players(p = nil)
   @players = p unless p.nil?
   @players
end

def chips(c = nil)
   @chips = c unless c.nil?
   @chips
end
end

def hand(name, &init)
h = Hand.new
yield(h) if block_given?
self.class.class_eval { define_method(name) { proc { h }.call } }
h
end

hand "my_hand" do |h|
h.players 10
h.chips 1000
end

puts my_hand.inspect

I took out &init, I understand why I don't need that in there.

However after doing all this, I'm not sure I get any benefit,
particularly if I stick to the more Rubyish players= and chips=

hand "my_hand" do |h|
  h.chips = 1000
  h.players = 10
end

vs

my_hand = Hand.new
my_hand.chips = 1000
my_hand.players = 10

It's basically the same...

Pat

···

On 5/8/06, James Edward Gray II <james@grayproductions.net> wrote:

On May 8, 2006, at 1:59 PM, Pat Maddox wrote:

> On 5/8/06, James Edward Gray II <james@grayproductions.net> wrote:
>> On May 8, 2006, at 1:38 PM, Pat Maddox wrote:
>>
>> > I'm writing a small app to do poker simulations. I read a lot of
>> > blogs in which the author shows off his cool DSL. I decided I
>> want to
>> > be able to specify a poker hand in my app like
>> >
>> > hand "my_hand" do
>> > players 10
>> > chips 1000
>> > end
>> >
>> > my_hand.foo
>> >
>> > How can I do something like that?
>>
>> class Hand
>> ...
>> end
>>
>> def hand( ..., &init )
>> Hand.new( ... ).instance_eval(&init)
>> end
>>
>> I really think you'll be happy in the long run though if you drop the
>> instance_eval() and pass the hand into the block instead.
>>
>> James Edward Gray II
>>
>
> Okay so now I have
>
> class Hand
> def players(p = nil)
> @players = p unless p.nil?
> @players
> end
>
> def chips(c = nil)
> @chips = c unless c.nil?
> @chips
> end
> end
>
> def hand(&init)
> yield(Hand.new) if block_given?
> end
>
> hand do |h|
> h.players 10
> h.chips 1000
> end
>
> Does that look right?

You can remove the &init parameter to hand(), since you are using
yield. You may also want to make players() and chips() more Rubyish
with players=() and chips=().

To keep the hand object you could have hand return it, or perhaps add
it to some global Hash by name.

Hope that helps.

James Edward Gray II