Showing posts with label ruby. Show all posts
Showing posts with label ruby. Show all posts

8/17/2013

Ruby Warrior - Game Emulation

Emulating the black box behavior allows us to build tests that prove your code works, as long, as the emulation remains close to the real thing. The Ruby Warrior runtime has features within it, that I do not know yet since I am still at level 7.

The output from my game emulator looks nice and allows me to great new alternative levels that exercise all the features of my player that I wish to.

GAME START
| ^     >|
|  ^    >|
|   ^   >|
|    ^  >|
|     ^ >|
|      ^>|
|       ^|
GAME OVER: ALIVE
GAME START
| ^ C   >|
|  ^C   >|
|  ^    >|
|   ^   >|
|    ^  >|
|     ^ >|
|      ^>|
|       ^|
GAME OVER: ALIVE
GAME START
| ^ S   >|
|  ^S   >|
|  ^S   >|
|  ^S   >|
|  ^S   >|
|  ^S   >|
|  ^S   >|
|  ^S   >|
|  ^S   >|
|  ^    >|
|   ^   >|
|    ^  >|
|     ^ >|
|      ^>|
|       ^|
GAME OVER: ALIVE

A simple rspec runner of these game layouts and a way to encode the game boards makes setup easy.

 describe "Game" do  
  let(:player) { Player.new }  
  
  it "plays empty board" do  
   game = Game.new("    >")  
   game.play(player)  
   
   player.should be_alive  
  end  
   
  it "rescues a sad caged pair of eyes" do  
   game = Game.new("  C  >")  
   game.play(player)  
   
   player.should be_alive  
  end  
   
  it "attacks some sludge" do  
   game = Game.new("  S  >")  
   game.play(player)  
   
   player.should be_alive  
  end  
 end  
   

The simple Game runner.

 class Game  
  def initialize(pieces)  
   @pieces = pieces  
  end  
   
  def play(player)  
   warrior = Warrior.new  
   warrior.board = Board.new(@pieces)  
   
   puts "GAME START"  
   while (warrior.alive? && warrior.on_board?) do  
    puts warrior.board.with_player_at(warrior.position)  
    player.play_turn(warrior)  
   end  
   puts "GAME OVER: #{warrior.alive? ? 'ALIVE' : 'DEAD' }"  
   
   warrior.alive?  
  end  
 end  
   

Ruby Warrior - Trying Again

It is clear that a solution to a problem like this can't just be imagined out of thin air. I am just not that smart. Just writing if statements was satisfying and productive to start with but once level 7 hit and I had to change direction there was no alternative but to throw everything away and start again.

This time, I decided to create a fake warrior implementation, an write some rspec tests to ensure that the actions I chose were appropriate. Then "release" (copy) that code to "production" (paste) to see if it worked there as well.

With this approach, I am making headway but can only solve level 2 because I haven't reimplemented the resting process yet.

Warrior Fake

class Warrior
  attr_accessor :position
  attr_accessor :board
  def self.at_position_1
    warrior = Warrior.new
    warrior.position = 1
    warrior
  end
  def self.next_to_sludge
    warrior = Warrior.at_position_1
    warrior.board = [:sludge]
    warrior
  end
  def initialize
    @position = 1 #zero based
    @attacked = false
    @board = []
  end
  def walk!
    @position += 1
  end
  def attack!
    @attacked = true
  end
  def has_attacked?
    @attacked
  end
  def feel
    @board
  end
end

Player Implementation

require './warrior_fake'
class Context
end
class Action
  def self.choose(warrior, context)
    if !warrior.feel.empty?
      Attack.new
    else
      Walk.new
    end
  end
end
class Walk
  def run(warrior)
    warrior.walk!
    warrior
  end
end
class Attack
  def run(warrior)
    warrior.attack!
    warrior
  end
end
class Player
  def initialize
    @context = Context.new
  end
  def play_turn(warrior)
    action = Action.choose(warrior, @context)
    action.run(warrior)
    warrior
  end
end

Specs

require './spec_helper'
require './warrior_fake'
require './warrior'
describe Player do
  let(:player) { Player.new }
  context "walking" do
    it "moves forward" do
      warrior = player.play_turn(Warrior.at_position_1)
      warrior.position.should == 2
    end
  end
  context "sludge" do
    it "notices sludge" do
      warrior = player.play_turn(Warrior.next_to_sludge)
      warrior.should have_attacked
    end
  end
end
describe Action do
  let(:context) { Context.new }
  let(:warrior) { Warrior.at_position_1 }

  context "construction" do
    it "walks forward" do
      action = Action.choose(warrior, context)
      action.should be_a Walk
    end
  end
end
describe Walk do
  it "forward" do
    walk = Walk.new
    warrior = walk.run(Warrior.at_position_1)
    warrior.position.should == 2
  end
end
describe Attack do
  it "forward" do
    attack = Attack.new
    warrior = attack.run(Warrior.next_to_sludge)
    warrior.should have_attacked
  end
end


Thank-you Ruby Warrior

I just ventured into the dungeons of the Ruby Warrior and spent an hour of my life that I can not get back, but would like to if that is at all possible. What a great time to be writing ruby, to program a knight, in a live dungeon.


I made it to Level 7 before my code was so complex that refactoring is inevitable. I count at least infinity code smells in this. Flags, single method, no intentional behavior, no single responsibility. I am considering some UI testing tool to prove that I can pass each level with the same codebase.

Good times.

class Player
  def play_turn(warrior)
    if !warrior.feel(:backward).empty?
      if warrior.feel(:backward).captive?
        warrior.rescue! :backward
        @saved_captive = true
      else
        warrior.attack! :backward
      end
    elsif !warrior.feel.empty?
      if warrior.feel.captive?
        warrior.rescue!
        @saved_captive = true
      else
        warrior.attack!
      end
    elsif warrior.health < 20
      if warrior.health < @health
        if warrior.health < 12
          warrior.walk! :backward
        else
          warrior.walk!
        end
      else
        warrior.rest!
      end
    else
      if @saved_captive
        warrior.walk!
      else
        warrior.walk! :backward
      end
    end
    @health = warrior.health
  end
end

10/07/2012

Ruby, SSL and Untrusted Certs

It has been a long time since focusing exclusively on writing Ruby code. So much fun.

The last two years have been groovy only which is a great language but there is something pure and simple about Ruby that just takes your breath away.

Enough of the emotional stuff, why, on earth, is it so hard to disable SSL cert trust verification. Such a common problem, google is full of Rails ActionMailer solutions but of coarse that doesn't help the rest of us.

Ruby 1.8.7

I approached the problem from Net:HTTP library makes it pretty easy. You just have to remember to require the correct classes and note that you are not disabling SSL just the trust verification part. # irb(main):001:0> require "net/https" # => true # irb(main):020:0> h = Net::HTTP.new("YOUR_SSL_SERVER",443) # => #<Net::HTTP YOUR_SSL_SERVER:443 open=false> # irb(main):021:0> h.use_ssl = true # => true # irb(main):022:0> h.verify_mode = OpenSSL::SSL::VERIFY_NONE # => 0 # irb(main):023:0> h.get("/") # => #<Net::HTTPOK 200 OK readbody=true>

My actual goal was to access a WSDL, over SSL, with an untrusted cert. This was not so easy. Took me about 5 hours to work out this solution. Expensive.

I used the Soap4R gem and since performance is not an issue I figured the dynamic proxy from the WSDL parsing would be the way to go:

factory = SOAP::WSDLDriverFactory.new("#{@url}?WSDL")

The problem was that there is no simple API to set the verify_mode of the connection so you have to root around in the code until you find where to monkey patch. This is what I came up with.

# # Monkey Patch HTTP Client # Sets SSL verify mode to NONE so that we can connect to an SSL server # that does not have a trusted certificate. # class HTTPAccess2::Client def initialize(*args) super(args[0], args[1]) @session_manager.ssl_config.verify_mode = OpenSSL::SSL::VERIFY_NONE end end

If someone has a cleaner solution I would love to hear it.

Ruby 1.9.3

Upgrading to 1.9.3 broke my Monkey Patch as expected so here is the updated one that handles both for the time being:

# # Monkey Patch HTTP Client # Sets SSL verify mode to NONE so that we can connect to an SSL server # that does not have a trusted certificate. # # The 1.8.7 patch adds a new constructor. # The 1.9.3 patch intercepts the existing constructor now that the class # name has changed. if RUBY_VERSION == "1.8.7" class HTTPAccess2::Client def initialize(*args) super(args[0], args[1]) @session_manager.ssl_config.verify_mode = OpenSSL::SSL::VERIFY_NONE #@session_manager.debug_dev = STDOUT end end else # > 1.8.7 class HTTPClient alias_method :original_initialize, :initialize def initialize(*args) original_initialize(args[0], args[1]) @session_manager.ssl_config.verify_mode = OpenSSL::SSL::VERIFY_NONE #@session_manager.debug_dev = STDOUT end end end

3/13/2009

Careful, Java Programmers going to Ruby

Good evening everyone, I am a Java programmer.
It happened quickly, I didn't even notice.
One day I was merrily strncpy'ing and the next it was immutable.


We joke about languages of old while new shinny languages are paraded in front of us, but in the end they all teach us something and make us forget other things.

Today I came across the first serious change that the Java world thrust upon my weak mind. I am working a Ruby project, a great new shinny language which is lots of fun to learn and work with.

When working in Java I use the usual Agile development process; write your test, write some code and repeat. As I progress, my code, and indeed the API design, evolve into a nice usable, stable set of libraries.

Working in Java, with Eclipse, the simplest technique is to start by writing your test, reference a public method, press a key to create it and flush out the implementation. As you go, you will naturally refactor pieces of code into new methods to keep it simple.

Well, this is where things get a little too easy for Java developers in Eclipse. To refactor a block of code into a new method just select it, press a couple of keys and Eclipse creates the new method for you. A new private method in the same class.

Sounds good right? Well it is, except, that you have now learned to not thing about the scoping your your methods when you create them. Your first is always public or protected because your test is driving it and subsequent methods are private by default as created by the IDE. It's a beautiful system.

Now you switch to Ruby.

You write your test and implement your public method, you refactor with the cut/paste/rename/suffle and low and behold, because you have learned not to think about it, you have loads of public methods in your class.

The project I am working on takes it one step further and has tests for every method, examining all its nuances, mocking all its dependencies and going to town making the implementation as couple to the test as possible. It's easy to do, they are all public, what else is a programmer to do?

Unit testing philosophy does vary depending on who you talk to but my basic goal is to:

  • Test all public methods,

  • Test all protected methods,

  • If a private method is particularly complex make it protected and test it,

  • If I have loads of "untested" private methods I need to move some to new classes and make them public. I leave it to you to quantify "loads".

  • Trust your coverage tool to tell you the private code you never use and delete it.


So, starting tomorrow, I change my Ruby development process and consider all new methods private unless part of a test driven process. This will do lots of things to improve the final product:

  1. Simplify the test/code dependencies making the tests less brittle.

  2. Prevent call sequence bugs where you have to call one method before another or it all falls over. Too many publics will do that you know.

  3. Make the calling conventions exposed by the class easier to grok by new programmers reading the code.

  4. Improve Class API design which is one of the primary benefits of TDD, lost to the lazy public manic people like me.



Oh, yes, an stop putting java semicolons in Ruby code. That really upsets the Ruby people.

1/22/2009

BDD test framework Shoulda

Behavior Driven Development is an interesting slant on testing. There appear to be many opinions on its advantages and disadvantages. At the end of the day, if you are testing, you have already won.

So, the question is, how can you tweak your method to improve on your bugs-per-line-of-code metric. This post isn't about that because I have no idea if BDD or Shoulda will help.

Shoulda is an alternative BDD framework to RSpec that has been argued about for so long. I can't help you with that either.

Instead, I just started using Shoulda in a Rails app so thought I would share some complaints, because being constructive is just too much work.

I switch a simple controller test over to Shoulda and it ran and passed but the original 3 tests that used to pass are now reported as "0 tests, 0 failures, 0 errors". While I proved that if there was an error it did explain precisely what was wrong to me, this 0 tests thing is severely demotivating. It is amazing how watching the number of tests grow in your project can encourage you to continue to strive for perfection.

IDE integration is always a problem with new stuff. NetBeans allows me to run a single test case with ctrl-shift F6 which is convenient if you have few that are suddenly failing. No such luck with the Shoulda version, all tests all the time.

However, all this is trivia compared to being able to do something like this:

require 'test/unit'
require 'shoulda'

class Lion
def speak
"rarrrr hickup"
end
end

class TestLion < Test::Unit::TestCase

context "the lion" do
setup do
@lion = Lion.new
end

should "say rarrr" do
assert_equal "rarrr", @lion.speak
end
end
end

and get this explanation of what you did wrong.

1) Failure:
test: the lion should say rarrr. (TestLion):
<"rarrrr"> expected but was <"rarrr hickup">.

Craft your feedback as carefully as you craft your output.

9/23/2007

JRuby Rails Project Day One, Lessons Learned

I blogged a while ago that Ruby was the way to go for the best language experience for the future. To that end I am starting to build a new site using Ruby on Rails and focusing on JRuby so that I can deploy it to my existing Tomcat hosting service.

The site is going to present a new company Sewing Seeds of Literacy which is a venture my wife is embarking on to help supply books to under privileged children. I was hired as the technical help.

Background over.

I started by using the NetBeans V6 IDE and its Ruby Rails integration. This is a major step forward in IDE Ruby support and integrates with JRuby easily.

So, right click, New Project, Ruby Rails Application, and you have your first Rails runtime on top of JRuby. This is really nice.

Initial setup over.

The first problem is the database access. The JRuby environment requires JDBC access. The database.yml setup is the same but there is an ActiveRecordJDBC gem that needs to be installed to manage the connection from ActiveRecord ORM library to the JDBC drivers.

This is all detailed on the Headius site.

Then these JDBC drivers need to be available on the classpath. I am going in with MySQL so I needed to add the mysql-connector-java-5.0.4-bin.jar to the classpath.

Unfortunately there are some competing configuration issues going on here.

1) I had downloaded and installed my own JRuby environment and NetBeans comes with its own. This causes problems because each environment installs its own gems. You can set the environment that NetBeans will use in

Tools->Options->Miscelanious->Ruby


2) I had my own c-ruby environment and my path specified jruby/bin before ruby/bin but the JRuby "rake" command is unix only so I was inadvertently running the c-ruby rake command expecting it to manage my migration properly but it couldn't find the JDBC gem.

Anyway, after much googling, Foo had the answer. You need to create a "jrake.bat" in your JRuby bin directory that looks like this:
@echo off
jruby -S rake %*


Now you can jrake in your jruby environment and rake in your c-ruby environment. There are references to "jake" here and there but nothing concrete.

3) Now that we are running the right commands we need to add the appropriate jar. There are a couple of ways to do this

o Create the CLASSPATH environment variable and point it to your jar.
o Copy your jar into the JRUBY_HOME/lib dir.

One thing that does NOT appear to work is adding the jar to the Netbeans project classpath.

I chose to copy to JRUBY_HOME/lib for the time being but I don't like this as a long term solution since it means each environment I deploy to needs some extra installation work. Ideally, the jars would be deployed with my war file so they are made available to the containers classpath automatically.

JDBC Jar configuration over.

Right click, generate, controller, simple. Right click, generate, model, no sweat. Right click, generate, migration, done.

These are basic Rails concepts that work just as well in a JRuby environment. They make application development very easy.

mysqladmin create MYDB_development
jrake db:migrate


Database creation over.

Now I have a model and a model test but I can't run them because there is no database. Yes, we just finished using our cool new migrations to create a database but that was the development database which is the default RAILS_ENV. We need the test database created from the same migrations. This is not so easy. In fact it is really hard. None of the books talk about it, all the migrations help pages just talk about the default development case. We are going to have to run our migration in test regularly and eventually in production as well so there has to be a solution.

Along comes a new plugin called Migrate Test DB Rake Plugin . This is a rails plugin that performs a database schema create on the test database before rails tests are run. This means that when you execute "jrake test" it will create the schema first. This is not effective when running Test::Unit in NetBeans.

So, I don't see that this is a good solution. As a side effect of testing I am able to create a test database schema. Still doesn't solve the production database situation but that is a little way off.

Model create over.

Oh, now I find the best documentation, on the JRuby Wiki. This entry talks about the "goldspike" plugin which adds lots of java'esk features to rake like creating a war and how to declare the mysql jar as a dependency.

2/26/2006

Another Hour Another Rails Release

While I am a complete novice at this and my controller tests still don't work I have been able to add basic delete and create functionality to "WebZone On Rails" in about 5 hours.

The reason I couldn't do this in Java is because of ActiveRecord and the tight integration between the controller and the page.

With ActiveRecord I have been able to create and delete from an existing MySQL schema with just a couple of lines of code. With the integrated mock data infrastructure that comes with Rails I have full unit tests for all these steps.

With the tight integration of controller and page I am able to create controller instance variables and directly reference them from the rhtml pages. This makes it mind blowingly easy to load data and reference that data directly on the page while maintaining the MVC isolation. This is similar in concept to the .Net idea of the page and code behind being the same instance.

I still can't run my controller tests. Ran the gem update rails with no improvement.

Publishing Rails with SwitchTower

I need a simpler way to get my changes out to the web site. currently I am just copying file by file to FTP but this is tedious and error prone. I have heard that Switch Tower is the tool of choice for deploying Rails apps so here goes:


gem install switchtower


The install seemed to go well with the following dependencies also being installed.


Attempting local installation of 'switchtower'
Local gem file not found: switchtower*.gem
Attempting remote installation of 'switchtower'
Updating Gem source index for: http://gems.rubyforge.org
Install required dependency net-ssh? [Yn] y
Install required dependency needle? [Yn] y
Install required dependency net-sftp? [Yn] y
Successfully installed switchtower, version 1.0.1


Switch Tower needs to make some changes to the current rails app so that it can deploy it.


switchtower --apply-to [full path to rails app]


This seems easy enough but the first run gives me this. After a hour of google searching and drilling down into the gem install I find that the error, is infact, correct, the rails_generator/sripts/generate code does not exist as part if the switchtower install but I don't know where to get it so I am stuck.


d:/products/ruby-1.8.2-14/lib/ruby/site_ruby/1.8/rubygems/loadpath_manager.rb:5:
in `require__': No such file to load -- rails_generator/scripts/generate (Missin
gSourceFile)
from d:/products/ruby-1.8.2-14/lib/ruby/site_ruby/1.8/rubygems/loadpath_
manager.rb:5:in `require'
from d:/products/ruby-1.8.2-14/lib/ruby/gems/1.8/gems/activesupport-1.2.
5/lib/active_support/dependencies.rb:214:in `require'
from d:/products/ruby-1.8.2-14/lib/ruby/gems/1.8/gems/switchtower-1.0.1/
lib/switchtower/generators/rails/loader.rb:7:in `load!'
from d:/products/ruby-1.8.2-14/lib/ruby/gems/1.8/gems/switchtower-1.0.1/
lib/switchtower/cli.rb:248:in `execute_apply_to!'
from d:/products/ruby-1.8.2-14/lib/ruby/gems/1.8/gems/switchtower-1.0.1/
lib/switchtower/cli.rb:219:in `execute!'
from d:/products/ruby-1.8.2-14/lib/ruby/gems/1.8/gems/switchtower-1.0.1/
lib/switchtower/cli.rb:12:in `execute!'
from d:/products/ruby-1.8.2-14/lib/ruby/gems/1.8/gems/switchtower-1.0.1/
bin/switchtower:11
from d:/products/ruby-1.8.2-14/bin/switchtower:19:in `load'
from d:/products/ruby-1.8.2-14/bin/switchtower:19

WebZone port to Rails

I have been using a product called WebZone since 2001. I built it to do what I want and have extended for me. It supports other users and sharing data with them but primarily it has always been for me.

Its primary goal is to allow me to collect information in one place and organize it. It does this with good support for drag and drop into the browser, JavaScript scriptlets that can add the current page to your WebZone account and the ability drag your information around your WebZone to relate it in anyway that you want.

WebZone on Java



At 5 years old it needs some serious re-writing. When I started it I was just getting into test first so it doesn't have many tests. It has no mock data so continuous testing is out.

Since Rails is getting so much press I have decided to try it our there.

Phase One. Allow a rails app to read and navigate a WebZone database.

Phase Two. Add edit feature.

Phase Three. Add delete feature.

Phase Four. Add create feature.

We are in Phase three and it is now deployed to

WebZone on Rails



So far so good.

The basic app was easy to create but I needed some ActiveRecord help from the XP Cincinnati team to get the database interface working nicely. Thanks to Jim Weirich.

With that part working, putting the rhtml files together to display the data was a snap.

A continuing problem is getting the controller tests working. So I am doing as much unit testing as possible but not being able to test the controller level is a serious problem. I am getting the error:


Exception: No url can be generated for the hash
{:targetId=>"1", :controller=>"read", :action=>"item", :targetType=>"TableText"}
generated_code/routing/generation.rb:5:in `generate_default_path'
.../action_controller/routing.rb:419:in `send'
.../action_controller/routing.rb:419:in `generate_path'
.../action_controller/routing.rb:415:in `generate'
.../action_controller/routing.rb:602:in `extra_keys'
.../action_controller/test_process.rb:86:in `assign_parameters'
.../action_controller/test_process.rb:295:in `process'
.../action_controller/test_process.rb:307:in `get'
webzone3/test/functional/read_controller_test.rb:20:in `test_item'