Archive for the ‘ruby’ Category

Ruby Factory Following the Open-Closed Principle

February 17th, 2009 by ScottK | No Comments | Filed in ruby

I had a rather chilling idea recently, how do you create a Ruby factory that follows the Open-Closed Principle. The open closed principle simply states that your code should be open for extension but not modification. More Here. That means unless it’s a true error or needs modification for a new feature, realistically, don’t modify it to support extensions (inheritance).

The processes I want to incorporate where A.) not case statements. Case statements for class resolution are a code smell in and of themselves, plus including new types breaks open/closed principle, B.) to achieve open/closed principle and load dynamically new classes need to be loaded on the fly. The reality was that it was relatively easy to accomplish, and I’m about to show you how.

We’ve all seen the class A inherits B namespace Y, blah blah blah articles. I’m throwing that out. Here’s the deal you go to the pet shop and you are asking the pet store owner for a lion. He has one and gives it to you. So you ask for a tiger, he doesn’t have one immediately so he checks in back; maybe he has one that just came in, or alerts you to the fact he has none.

Do you see the roles here? You are the consumer of the product provided by the pet shop. If the pet shop owner knows they have one in stock then they certainly give one.

If the pet shop owner doesn’t have one in stock then they need to investgate if they have one. /At this point in time if using case statements you need to add case “Tiger” :) /. In affect though that’s like asking the store owner to shut down the shop to research, since you would need to restart the application to take the new changes. That’s also breaking the open/closed principle since you are modifying the program to change a type return and not a feature.

Ok here’s where I ask that you create the PetShop to expand our zoo!

Create a file called pet_shop.rb and place the following:

require './lion'

module PetShop
  def PetShop.factory(arg)
    unless PetShop.const_defined?(arg)
      begin
	require "#{arg.downcase.to_s}.rb"
      rescue
	raise "Giving up since there does not appear to be a class for this module"
      end
    end
  PetShop.class_eval(arg)
  end
end

Now create a lion, which the store owner has in stock. call it lion.rb in the same directory as pet_shop.rb.

module PetShop
  class Lion

  end
end

Let’s take a stop here and evaluate this code.  First, the shop keeper is importing the lion that they know they have. It’d definitely scoped to the PetShop module because as a consumer we need to go there. Certainly you can argue over the “factory” name. I’ve seen it in many forms.

Here’s where it gets good though!

Once you call the module factory method with the type of animal you want to get several checks are performed. The

unless PetShop.const_defined?(arg)

Checks that the store owner already knows about the Lion. since we included it in the first require block then Lion instance is returned to you the consumer. via the:

PetShop.class_eval(arg)

Go ahead try this by firing up irb!

irb(main):001:0> require "pet_shop"
=> true
irb(main):002:0> lion = PetShop.factory("Lion")
=> PetShop::Lion
irb(main):003:0>

Don’t EXIT!!!1

We just proved the factory part and that the shop owner (Factory) knows it can return your specified type. What I still need to show is that you don’t have to modify this code and adhere to the open/close principle, nor do you have to shutdown your application to add new types. Just as you can’t tell the shop owner what type of animals they have and/or have them shut down their business.

So with that and the previous example still running in irb please create this file “tiger.rb” in the same directory as lion.rb and pet_shop.rb.

module PetShop
  class Tiger

  end
end

Clearly this is a brand new file. We didn’t modify the PetShop.factory. Now in the very same terminal that you called the PetShop.factory(’Tiger”) is want you to call:

irb(main):003:0> tiger = PetShop.factory("Tiger")
=> PetShop::Tiger

That specific part works like this:

    unless PetShop.const_defined?(arg)
      begin
         require "#{arg.downcase.to_s}.rb"
      rescue
          raise "Giving up since there does not appear to be a class for this module"
      end
    end

The unless operator makes sure that we have not required the class in the module instance. “Lion” was imported and therefore is true, “Tiger” was not and is therefore false. When the unless sees false it attempts to import the tiger.rb file. Being successful on the import then no exception is thrown and naturally the factory (shop owner) delivers the Tiger.

However calling:

irb(main):004:0> tiger = PetShop.factory("Bunny")
LoadError: no such file to load -- bunny.rb
	from ./pet_shop.rb:7:in `require'
	from ./pet_shop.rb:7:in `factory'
	from (irb):4
	from :0

Because there is no bunny.rb file. Nor was bunny defined in the lion.rb file.

The factory pattern and open/close principle has been around for ages (OOD lifetime), yet I’ve seen so many software applications resort to everything from if/elses to case statements. I know; Refactoring these is such a huge effort that’s it’s so easy to just go along with.

I hope that in this Ruby example that factories really are easily done as well as make your code a whole lot more extensible, as well as a whole lot less refactorable!

Tags: , , , , ,

Finding The True Domain Using Ruby On Rails

November 3rd, 2008 by ScottK | 3 Comments | Filed in ruby

So here’s the problem your Ruby on Rails takes on url and another url. You then need to compare these two inputs to make sure they reside on the same domain. http://techraving.com has the same true domain as https://news.techraving.com. However, http://news.techraving.com does not reside on http://www.yahoo.com. What about http://localhost:8080 as being the same domain as http://localhost:443/index.html.

You could write an overly complication set of methods to start detecting string positions, or even incorporating a bunch of gsub regexs to try and weed out the unwanted components. Or you could take the easy route and call the URI module.

The URI module easily breaks the string url into it’s different parts which you can use to further refine using array’s into what you need for comparison. Taking these two domains:

http://www.techraving.com/about/

http://news.techraving.com/about/

We need to find out whether they are on the same domain. So:

first_domain = URI.parse("http://techraving.com/about/")
second_domain = URI.parse("http://news.techraving.com/about/")

Now first_domain and second_domain are both distinct instances of the URI object. The next step is to let these objects return us the host by calling “host”:

>> first_domain.host
=> "techraving.com"

>> second_domain.host
=> "news.techraving.com"

That was a lot of work already done for us. But we are not done yet! we still need to find the true domain. Or if you notice that would be the last two index of a possible array. So let’s split into an array:

>> first_array = first_domain.host.split(".")
=> [ "techraving", "com"]

>> second_array = second_domain.host.split(".")
=> ["news", "techraving", "com"]

So the array’s are what we expect in that the last two are the parts we need. Now how best to grab them. Easy enough!

unless first_array.size == 1
  first_true_domain = first_array[first_array.size - 2] << "." << first_array[first_array.size - 1]
else
  first_true_domain = first_array[0]
end

unless second_array.size == 1
  second_true_domain = second_array[second_array.size - 2] << "." << second_array[second_array.size - 1]
else
  second_array_true_domain = second_array_array[0]
end

Now why can the array size equal 1? That’s because:

>> local_array = URI.parse("http://localhost:80").host.split(".")
=> ["localhost"]

and,

rent a car bulgaria>> local_array = URI.parse("http://localhost:8080").host.split(".")
=> ["localhost"]

Both are 1 array size and yet the same domain.

So now that we have that out of the way why the index subtraction in the indexes. Because array.size – 2 returns the domain name and array.size – 1 returns the generic top-level domain we can know put the two together by concatenating these two with the “.” to get the true domain.

Now (first_true_domain == second_true_domain) comparisons can be made without sub-domain or port problems. And a ton less string position/replace code.

Building Gems on Ubuntu

October 11th, 2008 by ScottK | 3 Comments | Filed in ruby

I thought I would just pop in and tell you how on a fresh install of Ubuntu 8.04 I ran into some issues trying to get ruby gems to install. After some research and poking/prodding I’ve come up with the solutions.

Being that this is a fresh install of Ubuntu I did go ahead and apt-get ruby1.8 and rubygems just to kick things off a bit before installing rails and my reguire gems. After the apt-get rubygems install I wanted to update the gems I had by running “sudo gem update –system”. That ran fine.

So now was the time to install rails by using “sudo gem install rails” Big fail as I got an error. “/usr/bin/gem:24: uninitialized constant Gem::GemRunner (NameError)
” Well shit! After some looking it seems that you can add this line to the /usr/bin/gem file: “require ‘rubygems/gem_runner’” after the “require ‘rubygems’”.

require 'rubygems'
# Add the below line
require 'rubygems/gem_runner'

That worked fine for the rails install. However I ran into a new problem. “extconf.rb:1:in `require’: no such file to load — mkmf (LoadError)”. This was easily fixed by “sudo apt-get install ruby1.8-dev”. Seems that some gems require the ruby source files to build. Having them is necessary.

However…

Those that needed the ruby dev started to throw a ton of errors during the “make” portion. It turned out I also needed to “sudo apt-get install g++” as well.

Once I did that all gems installed just fine. So if you have just installed Ubuntu Hardy Haron or are getting any of the three errors then there is what I did. Make sure to edit the /usr/bin/gem file. apt install ruby1.8-dev and g++.

Tags: , ,