Tuesday, November 17, 2015

Maintaining keyword arity is hard

You know, sometimes you just can't bother with explicitly stating what keyword arguments that you want to pass.

Monday, October 5, 2015

DRY up your class definitions

Have you ever felt vaguely annoyed at typing the class name in the file name and then typing it again inside the file as well? Have you ever changed a class name and forgotten to change the file name?

Well I have good news for you!


Here is the code! This class allows you to condsolidate the declaration of class names into the file name. It also handles namespacing based on the file path if you are using Rails autoloading.

This works with the single exception of constant lookup via nesting, so you will need to replace constants with variables and methods.

Sunday, January 25, 2015

How to reverse an array in Ruby in O(1)

class ReverseArray < Struct.new(:array)
  include Enumerable
  def each(&blk)
    i = array.length - 1
    while i >= 0 do
      yield array[i]
      i -= 1
    end 

  end
end

array = (0..10000).to_a
reverse_array = ReverseArray.new(array)

array.last == reverse_array.first
=> true

Friday, October 17, 2014

Superlet

Lets say you are testing your app superhero in RSpec:

RSpec.describe Superhero do
  subject(:superhero) { Superhero.new }

  it { is_expected.to be_super }
end


This superhero is sad because he has no powers though. So lets try giving him x-ray vision:

RSpec.describe Superhero do
  subject(:superhero) { Superhero.new }

  it { is_expected.to be_super }
  it { is_expected.not_to have_xray_vision }

  context "when given x-ray vision" do
    subject(:superhero) { Superhero.new(:xray_vision) }
    it { is_expected.to have_xray_vision }
    it { is_expected.to be_super }
  end
end


And now we want x-ray vision and flight:

RSpec.describe Superhero do
  subject(:superhero) { Superhero.new }

  it { is_expected.to be_super }
  it { is_expected.not_to have_xray_vision }
  it { is_expected.not_to have_flight }

  context "when given x-ray vision" do
    subject(:superhero) { Superhero.new(:xray_vision) }

    it { is_expected.to be_super }
    it { is_expected.to have_xray_vision }
    it { is_expected.not_to have_flight }

    context "when given flight" do
      subject(:superhero) { Superhero.new(:xray_vision, :flight) }

      it { is_expected.to be_super }
      it { is_expected.to have_xray_vision }
      it { is_expected.to have_flight }
    end
  end
end


This test looks pretty nice, but we would like it to be dry in case we want to change the names of the powers to fight a new supervillain. First lets use the power of arrays and the splat:

RSpec.describe Superhero do
  subject(:superhero) { Superhero.new *powers }
  let(:powers) { Array.new }

  it { is_expected.to be_super }
  it { is_expected.not_to have_xray_vision }
  it { is_expected.not_to have_flight }

  context "when given x-ray vision" do
    let(:powers) { [:xray_vision] }

    it { is_expected.to be_super }
    it { is_expected.to have_xray_vision }
    it { is_expected.not_to have_flight }

    context "when given flight" do
      let(:powers) { [:xray_vision, :flight] }

      it { is_expected.to be_super }
      it { is_expected.to have_xray_vision }
      it { is_expected.to have_flight }
    end
  end
end


Next we can use the super power of lets, super():

RSpec.describe Superhero do
  subject(:superhero) { Superhero.new *powers }
  let(:powers) { Array.new }

  it { is_expected.to be_super }
  it { is_expected.not_to have_xray_vision }
  it { is_expected.not_to have_flight }

  context "when given x-ray vision" do
    let(:powers) { super() << :xray_vision }

    it { is_expected.to be_super }
    it { is_expected.to have_xray_vision }
    it { is_expected.not_to have_flight }

    context "when given flight" do
      let(:powers) { super() << :flight }

      it { is_expected.to be_super }
      it { is_expected.to have_xray_vision }
      it { is_expected.to have_flight }
    end
  end
end


Woah, now we have perfectly dried up our tests, but how on Krypton does this work?

#describe and #context are aliases and both create classes descended from RSpec::Core::ExampleGroup, but the magic is that each example group is also a subclass of the example group that it is contained in so any methods defined within an example group can be accessed by its children. The innermost example group defined above will return this if you ask for its ancestors:

[RSpec::ExampleGroups::Superhero::WhenGivenXrayVision::WhenGivenFlight, RSpec::ExampleGroups::Superhero::WhenGivenXrayVision, RSpec::ExampleGroups::Superhero, ...]

The other half of this equation is that #let defines a method on the example group it is contained within. This means that every one of the classes listed in that ancestor list has the method #powers defined on it, and through the power of inheritance you can access #powers on the parent example group with the call to super().

Friday, August 1, 2014

RSpec Advanced Subject

So, as we all know, we shouldn't use subject. But what if you really like one liner syntax?

I am working on an attempt to make subject more dynamic and allow the use of one lines in more places. I am doing this by parsing describe arguments and adding a couple new blocks in order to build the subject dynamically.

For example:

describe Object do
  describe '#nil?' do
    it { should be_false }
  end
end

Will be parsed to know that the subject under test is the following: Object.new.nil?

What about class methods and methods with arguments?

describe File do
  describe '.read' do
    when_passed 'file.txt' do
      it { should eq('contents of file.txt') }
    end
  end
end

This will be parsed as
File.read('file.txt'). This works by storing the method, what the method is called on, and what is passed to the method and putting it all together within a proc that is called as the hidden subject. A period before the method indicates it is a class method and a hash indicates it is an instance method.

Finally there is a way to pass variables to the initializer:


describe Array do
  when_initialized_with 2 do
    it { should eq [nil, nil] }
  end
end

This is just the basics and I am looking for feedback and more feature ideas. Currently I am trying to figure out passing blocks and how #let fits in.

rspec-advanced_subject


Thursday, July 5, 2012

Reverse Polish Notation

I came up with an algorithm to convert infix expressions to rpn at work the other day while trying to think about how to create and store logical expressions and upon not immediately finding any Ruby gems that do rpn conversions I decided to make it my FIRST EVER GEM omgroflbbq.

Anyway, it turned out my original idea of storing an insert point doesn't work when you have things like operator precedence, so I punted to wikipedia and found this:

http://en.wikipedia.org/wiki/Shunting-yard_algorithm

One hour later I had a fully speced gem covering converting simple algebra.

https://rubygems.org/gems/rpn-converter
https://github.com/kwstannard/rpn-converter

Tuesday, February 7, 2012

The tower defense

Let's say you are playing a tower defense with multiple lanes. This is going to be a simple tower defense with 3 lanes. Each lane sends out a baddie with a certain amount of health every second. In each lane you must put one tower. The baddies will be something like as follows:

Lane 1 - 250 health
Lane 2 - 150 health
Lane 3 - 50 health

You have several choices for towers. 3 of them deal a certain amount of dps, but can hit any lane. I will call these pool towers since they pool their damage. The 4th tower deals an infinite amount of dps, enough to kill any baddie, but can only deal damage in its lane. Let's say the towers are as follows:

Lava - infinite dps, 70 gold/second - its lane only 
Lightning - 400 dps, 155 gold/second - pool tower
Ordnance - 90 dps, 65 gold/second - pool tower
Plasma - 45 dps, 45 gold/second - pool tower
Conduit - 0 dps, 20 gold/second - pool tower

Now, the point of this tower defense is not just to survive, which would be easy, but to do so in the most cost efficient way possible, so while you might want to put down an infinite dps tower in every lane it probably isn't your best choice.

This is a simple problem and you probably already solved it. But, what if there was a million lanes? What if there was a restriction on the conduit towers so that you can only use one of them per lightning or plasma tower? What if there was even more towers that act like the lightning tower but with different prices and dps?

Here is the way that I solved this in O(nlog(n)) time. First you need to create a list of baddies sorted by health with lowest health first. This is the log(n) of the nlog(n). If the list is already given to your sorted, all the better.

Now place Lava towers on every lane and record the total cost somewhere and call it the cheapest known cost.

What we are going to do next is work our way down the lane list, replacing one lava tower at a time with a pool tower and keeping a running total of bad guy health and the total dps of the pool towers. If you can replace the lava tower with the cheapest available tower without the total bad guy health exceeding the pool dps then pick that, and if not then pick the most cost efficient pool tower.

In this simple example, this gives you the choice of either the conduit or the lightning towers. In a more complex game, the conduit tower might not be available due to restrictions and the cheapest possible tower to place might be a plasma.

After each tower replacement check the new total cost against the cheapest known cost. If it is cheaper then record the new cheapest known cost and keep moving down the list.

Eventually you will reach a point where adding a new lightning tower may not deal enough damage to maintain tower damage above the total baddie health. You are now done with trying to replace lava towers. Take the final cheapest known tower configuration, total damage, and total baddie health in lanes with pool towers and move on. In the simple example above you would end up with 2 conduits and a lightning for your towers, 400 damage, and 400 baddie health.

Your next step is to determine whether you can trade a lightning tower for an ordnance or maybe a plasma tower while still being able to kill all the baddies. If you can, then do so. In the example above this is not possible.

The final step is only needed if there was a restriction on the conduit towers and you might end up in a situation where you can replace two plasma towers for an ordnance and a conduit. If so then do that.

Congratulations, you now have the cheapest possible tower configuration.