0

I am currently working on a Poker game in Ruby. Instead of using numerous if-else statements to check the value of the player's hand, I decided to do the following:

  #calculate the players score
  def score
    POSS.map {|check|
      if (check[1].call())
        @score = check[0]
        puts @score
        return check[0]
      else
        false
      end
    }
  end

      POSS = [
    [10, :royal_flush?],
    [9, :straight_flush?],
    [8, :four_kind?],
    [7, :full_house?],
    [6, :flush?],
    [5, :straight?],
    [4, :three_kind?],
    [3, :two_pairs?],
    [2, :pair?]
  ]

The second item in each item of 'POSS' is a method I created to check whether the player has that hand. I am attempting to call the method with .call(), but get the following error:

Player.rb:43:in `block in score': undefined method `call' for 
:royal_flush?:Symbol (NoMethodError)    from Player.rb:42:in `map'  from
Player.rb:42:in `score'     from Player.rb:102:in `get_score'   from
Player.rb:242:in `<main>'
kittykittybangbang
  • 2,380
  • 4
  • 16
  • 27

3 Answers3

2

http://ruby-doc.org/core-2.2.2/Object.html Object#send is the method you are looking for.

Since you are wanting a 'class method', then Object should be self when declaring instance methods of the class that contains the 'class methods'

Try this code

 #calculate the players score
  def score
    POSS.map do |check|
      if self.send check[1] 
        @score = check[0]
        puts @score
        return check[0]
      else
        false
      end
    end
  end

      POSS = [
    [10, :royal_flush?],
    [9, :straight_flush?],
    [8, :four_kind?],
    [7, :full_house?],
    [6, :flush?],
    [5, :straight?],
    [4, :three_kind?],
    [3, :two_pairs?],
    [2, :pair?]
  ]

Styles vary from person to person, however, I think when using multi line blocks, it would be best to use 'do,end' pair instead of '{ }'

https://github.com/bbatsov/ruby-style-guide

I think some confusion may come from code that looks like this

foobar = ->(foo,bar){puts "Passed in #{foo}, #{bar}"}
foobar.call("one","two")

If the first line was abstracted into other parts of the program you may have thought that foobar was a method, but its really a lambda. Procs and Lambdas are just like methods but better.. in their own way.. Check out this article on Procs, Blocks and Lambdas.

http://www.reactive.io/tips/2008/12/21/understanding-ruby-blocks-procs-and-lambdas/

But also if interested check out https://www.codecademy.com/forums/ruby-beginner-en-L3ZCI for more detailed hands on with PBLS

Schylar
  • 774
  • 1
  • 5
  • 13
0

No method is no method; and there is no Symbol#call which causes the immediate error.

The (or rather, a) way to call is via Object#__send__, supplying the name and arguments. One could also resolve a method and then call that; but __send__ is the most direct route as Ruby is based on message passing.

That is, instead of symbol.call(..), use obj.__send__(symbol, ..). (In this case the object would probably be self.)

See Understanding Ruby symbol as method call

Community
  • 1
  • 1
user2864740
  • 60,010
  • 15
  • 145
  • 220
  • It continues to give me the same error. I have royal_flush? defined earlier and it works when tested individually. Here is what my call looks like with your suggested changes: POSS.map {|check| if (Player.send check[1]) – Power Project Jul 18 '15 at 04:06
  • @PowerProject No method is no method. If it gives the same error (it will be the same *type* of error, but for a different receiver object and method name) then see previous. A method named `x` has to be present on `obj` when using `obj.__send__(:x)`. In this case you probably don't want to use `Player` (a class), but rather a *particular* player instance. If you do want to use a class, make sure that *class methods* are used. – user2864740 Jul 18 '15 at 04:07
  • The problem was that I was doing Player.send instead of self.send as mentioned by @Schylar – Power Project Jul 18 '15 at 04:12
  • @PowerProject See the relevant linked documentation. Such is how `__send__` works. – user2864740 Jul 18 '15 at 04:15
0

You can use send.

class Foo
  def self.bar
    "bar"
  end

  def baz
    "baz"
  end
end

Foo.send(:bar) # => "bar"
f = Foo.new
f.send(:baz) # => "baz"

Though I'm not sure this is the best approach for the app you're writing. When you get it working you can post it on CodeReview.

Community
  • 1
  • 1
jcm
  • 1,781
  • 1
  • 15
  • 27