simpleCMS on github

July 24th, 2008 by charlie

Moved simpleCMS over to github.

There were quite a few changes that were required to get it working with rails 2.1, so they are in the repository now.
So to install, you pretty much follow the same instructions from before.

The only thing I have not completely resolved is the use of the simple_cms_item partial that sits in the plugin's app/views/shared directory. I tried forever to use append_view_path to share the partial over. That worked, as in it found the partial, but the application layout went away, so instead, you can just copy the partial to your RAILS_ROOT/app/views/shared directory for now.

Additionally, you can install it through github: script/plugin install git://github.com/pullmonkey/simple_cms.git
And of course, a lot of you have asked how to just plain download it, well you can do that here, find the download button and click :)

Let me know how it goes.

Ok, already, I heard ya :) The open flash chart (version 2 - OFC2) plugin is done (really just started) and it is out on github.

I rewrote the open flash chart plugin (started from scratch) to work with json like teethgrinder does here.
This time I think it is much slicker and a lot easier to work with.
I haven't tried much more than bar graphs, all the functionality is there for other types of graphs, just not tested.
So it is out there, and if you are willing to try it out, here is how:
  1. rails testing_ofc_2
  2. cd testing_ofc_2
  3. script/plugin install git://github.com/pullmonkey/open_flash_chart.git
  4. script/generate controller test_it
  5. Add the following to the test_it_controller.rb in RAILS_ROOT/app/controllers:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    
    
    class TestItController < ApplicationController
      def index
        @graph = open_flash_chart_object(600,300,"/test_it/graph_code")
      end
    
      def graph_code
        max = 20
        tmp = []
        10.times do |x|
          tmp << rand(max)
        end
    
        title = Title.new("MY TITLE")
        bar = BarGlass.new
        bar.set_values([1,2,3,4,5,6,7,8,9])
        chart = OpenFlashChart.new
        chart.set_title(title)
        chart.add_element(bar)
        render :text => chart.to_s
      end
    end
    
    
  6. Add the following to index.html.erb in RAILS_ROOT/app/views/test_it/:
    1
    2
    3
    4
    5
    
    
    <script type="text/javascript" src="/javascripts/swfobject.js"></script>
    <%= @graph %>
    
      
  7. Copy swfobject.js from the plugin's assets/ directory (will make this happen at install time later) to your RAILS_ROOT/public/javascripts directory
  8. Copy open-flash-chart.swf from the plugin's assets/ director to your RAILS_ROOT/public/ directory
  9. script/server
  10. Let me know how it goes, thanks.


Ruby on Rails - Multiple database connections

April 21st, 2008 by charlie

Found a need for this information while answering questions on railsforum.
So, let's say that we want to use two databases and let's even say that we want to use an Oracle database and a MySQL database. How can this be done? To start, we must decide which database will be our default database. In this scenario, I chose MySQL. Let's see what that looks like:
1
2
3
4
5
6
7
# in your database.yml file
development:
  adapter: mysql
  username: root
  password: 
  database: example_development

So we have all seen that before. Now all of our active record models will use this mysql connection.
But, I need to use data from an oracle database, so let's setup that connection:
1
2
3
4
5
6
7
8
9
10
11
12
13
# in your database.yml file
development:
  adapter: mysql
  username: root
  password: 
  database: example_development

oracle_development:
  adapter: oracle
  username: root
  password: 
  database: example_oracle_development

Neat, we have two development connections. Now we have to tell which models to use which connection. Well, actually, we just need to tell the oracle models to connect to oracle_development, all the other models will default to development. I have a model named user, and it's records are kept in an oracle database. Our user model looks like this initially:
1
2
3
4
#RAILSROOT/app/models/user.rb
class User < ActiveRecord::Base 
end

The line we need to add is this:
1
2
establish_connection :oracle_development

Even better, we can make this dynamic, so when we are in the test or production environment, we don't need to change the establish_connection line.
1
2
3
# use RAILS_ENV where RAILS_ENV is generally development, test or production
establish_connection "oracle_#{RAILS_ENV}"

So the final product could look something like this:

database.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
dev_basics: &dev_basics
  username: root
  password: 

<% %w(development test production).each do |env| %>
<%= env %>:
  <<: *dev_basics
  adapter: mysql
  database: example_<%= env %>

oracle_<%= env %>:
  <<: *dev_basics
  adapter: oracle
  database: example_oracle_<%= env %>
<% end %>

Oracle model example

1
2
3
4
class User < ActiveRecord::Base 
  establish_connection "oracle_#{RAILS_ENV}"
end


That should be it.

Ok, great news. I have fixed a fairly large bug, Even better news, you probably never noticed it unless you were trying to output graphs via javascript, I.e., using graph.set_output_type("js").
Thanks go to Brandon, who provided an example of using javascript as the output type:

View Source Code
So if this was affecting you, then you will want to get the latest version of the plugin - Instructions.

Ruby - include? versus intersection

April 2nd, 2008 by charlie

After my last article about intersection and arrays, I got to thinking how this could apply elsewhere.
I decided to see if I could write a faster include?() method for Array using the intersection operator. So here is what I did:

1) Tested via irb (of course)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

[pullmonkey]$ irb
# build the array for conceptual testing
irb(main):003:0> a = [1,2,3]
=> [1, 2, 3]
# see how include?() does it
irb(main):004:0> a.include?(2)
=> true
irb(main):005:0> a.include?(4)
=> false
# see what could be done with intersect
irb(main):006:0> a & [2]
=> [2]
irb(main):007:0> (a & [2]).empty?
=> false
# this should return true, so negate it
irb(main):008:0> !(a & [2]).empty?
=> true
irb(main):009:0> !(a & [4]).empty?
=> false

2) Extended the Array class with the faster_include?() method:

1
2
3
4
5
6

class Array
  def faster_include?(n)
    !(self & [n]).empty?
  end
end

3) Wrote a performance test comparing elapsed time for true and false results:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# size of the array
x = 4000000
# build the array
a = (1..x).to_a
p "Finding #{x/2} ..."
t1 = Time.now
p "include?() - returns true: #{a.include?(x/2)}"
t2 = Time.now
p "faster_include?() - returns true: #{a.faster_include?(x/2)}"
t3 = Time.now
p "include?() - returns false: #{a.include?(-50)}"
t4 = Time.now
p "faster_include?() - returns false: #{a.faster_include?(-50)}"
t5 = Time.now
p "Elapsed time for include?() returning true: #{t2 - t1}."
p "Elapsed time for faster_include?() returning true: #{t3 - t2}."
p "Elapsed time for include?() returning false: #{t4 - t3}."
p "Elapsed time for faster_include?() returning false: #{t5 - t4}."

4) Just to see if there was a difference I got results and here they are:

Attempt 1:
1
2
3
4
5
6
7
8
9
10

"Finding 2000000 ..."
"include?() - returns true: true"
"faster_include?() - returns true: true"
"include?() - returns false: false"
"faster_include?() - returns false: false"
"Elapsed time for include?() returning true: 0.308243."
"Elapsed time for faster_include?() returning true: 0.271465."
"Elapsed time for include?() returning false: 0.629375."
"Elapsed time for faster_include?() returning false: 0.242673."
Attempt 2:
1
2
3
4
5
6
7
8
9
10

"Finding 2000000 ..."
"include?() - returns true: true"
"faster_include?() - returns true: true"
"include?() - returns false: false"
"faster_include?() - returns false: false"
"Elapsed time for include?() returning true: 0.323652."
"Elapsed time for faster_include?() returning true: 0.272212."
"Elapsed time for include?() returning false: 0.594751."
"Elapsed time for faster_include?() returning false: 0.277882."
Note that faster_include?() is consistent in elapsed time for a result of true and a result of false. However, include?() takes much longer in both attempts to return false than it does to return true, well actually about twice as long. include?() goes through each element, and I am using the midway point of the array in all tests, so it makes sense that include?() would return true in half the time it would take to return false. Very interesting, so now that I see performance improvement with faster_include?(), I need to do a wider spread of tests and for more attempts:

5) Better testing:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

results = {}
n = 5
# size of the array
[1,50,500,5000,5000000].each do |x|
  a = (1..x).to_a
  n.times do |t|
    # build the array
    t1 = Time.now
    a.include?(x/2)
    t2 = Time.now
    a.faster_include?(x/2)
    t3 = Time.now
    a.include?(-50)
    t4 = Time.now
    a.faster_include?(-50)
    t5 = Time.now
    results[x]          ||= {}
    results[x]["true"]  ||= []
    results[x]["false"] ||= []
    results[x]["true"]  << (t2 - t1) - (t3 - t2)
    results[x]["false"] << (t4 - t3) - (t5 - t4)
  end
  detailed_results = results
  results[x] = {"true" => detailed_results[x]["true"].sum / n, "false" => detailed_results[x]["false"].sum / n}
end
pp results

My new results:

The results are based on 5 attempts for each array for both true and false for a total of 50 attempts.
1
2
3
4
5
6

{5000000=>{"true"=>0.0921126, "false"=>0.4374644},
 5000=>{"true"=>5.84e-05, "false"=>0.0004404},
 500=>{"true"=>1.4e-06, "false"=>4.16e-05},
 50=>{"true"=>-3.4e-06, "false"=>1.0e-06},
 1=>{"true"=>-4.8e-06, "false"=>-3.8e-06}}
Note that arrays with 50 items or less seem to perform better using include?(), but barely. On the other hand with an array of 5M items, you shave off half a second using faster_include?().

So there you have it, faster_include?() can keep its name :)

Intersection of Array of Arrays - Ruby

March 31st, 2008 by charlie

Have you ever needed to retrieve the intersection of arrays in an array. Well, I did.
Let's say that you have a has and belongs to many (habtm) association between articles and tags, (I.e., a tag habtm articles and an article habtm tags). This means that tag.articles will return a list of articles that have that tag and article.tags will return the tags of the article. So if a user wants to search your blog for all articles that have 'tag1' and 'tag2', you would return all common articles.
Picture a search page with a list of check boxes, one for each tag that you have. The user can click as many tags as they want and then it is your job to find the common articles between them. The search POST contains the ids of the selected tags, like params[:tag_ids] = ["1", "3", "15"] or something. Let's go with this example.
1) The first step is to find those tags:
1
>> tags = Tag.find(params[:tag_ids])
2) Next, we want to get the articles associated with each tag, we will work with the ids:
1
2
>> tags.map(&:article_ids)
=> [[1,2,3],[2,3,4,5],[2,3,6]]
So we have our array of arrays of article ids.
3) Turn each sub array into a string like "[1,2,3]"
1
2
>> tags.map(&:article_ids).map(&:to_json)
=> ["[1, 2, 3]", "[2, 3, 4, 5]", "[2, 3, 6]"]
4) Join by the intersection symbol (&) like this:
1
2
>> tags.map(&:article_ids).map(&:to_json).join("&")
=> "[1, 2, 3]&[2, 3, 4, 5]&[2, 3, 6]"
5) Run eval() against this string:
1
2
>> eval(tags.map(&:article_ids).map(&:to_json).join("&"))
=> [2,3]
This means that the tags we selected have common articles with ids of 2 and 3.
So a one-liner would be:
1
2
>> Article.find(eval(Tag.find(params[:tag_ids]).map(&:article_ids).map(&:to_json).join("&")))
=> <returns an array of article objects>


Dynamic Select Boxes - Ruby on Rails

March 30th, 2008 by charlie

I have seen this asked a lot in the forums, so I thought I would write up a little tutorial.
For this tutorial I am going to have three select boxes. The first select box will be a super category of the next two select boxes and the second select box will be a super category of the third select box. I hope that makes sense. To demonstrate, I thought I would use Genre -> Artist -> Song. So let's get started:
Create your models and build your migrations:
1
2
3
4

ruby script/generate model genre name:string
ruby script/generate model artist name:string genre_id:integer
ruby script/generate model song title:string artist_id:integer
Populate your genres, artists and songs through a migration:
1
2

ruby script/generate migration create_hierarchy
Contents of migration:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

class CreateHierarchy < ActiveRecord::Migration
  def self.up
    g1 = Genre.create(:name => "Genre 1")
    g2 = Genre.create(:name => "Genre 2")
    g3 = Genre.create(:name => "Genre 3")

    a1 = Artist.create(:name => "Artist 1", :genre_id => g1.id)
    a2 = Artist.create(:name => "Artist 2", :genre_id => g1.id)
    a3 = Artist.create(:name => "Artist 3", :genre_id => g2.id)
    a4 = Artist.create(:name => "Artist 4", :genre_id => g2.id)
    a5 = Artist.create(:name => "Artist 5", :genre_id => g3.id)
    a6 = Artist.create(:name => "Artist 6", :genre_id => g3.id)

    Song.create(:title => "Song 1",  :artist_id => a1.id)
    Song.create(:title => "Song 2",  :artist_id => a1.id)
    Song.create(:title => "Song 3",  :artist_id => a2.id)
    Song.create(:title => "Song 4",  :artist_id => a2.id)
    Song.create(:title => "Song 5",  :artist_id => a3.id)
    Song.create(:title => "Song 6",  :artist_id => a3.id)
    Song.create(:title => "Song 7",  :artist_id => a4.id)
    Song.create(:title => "Song 8",  :artist_id => a4.id)
    Song.create(:title => "Song 9",  :artist_id => a5.id)
    Song.create(:title => "Song 10", :artist_id => a5.id)
    Song.create(:title => "Song 11", :artist_id => a6.id)
    Song.create(:title => "Song 12", :artist_id => a6.id)
  end

  def self.down
# you can fill this in if you want.
  end
end
Yes, I know it is generic data, sorry. So anyway, as you can see there are 3 genres, each with 2 artists, for a total of 6 artists each with 2 songs for a total of 12 songs. Each genre has 4 songs through its artists. Ok, so now we need to populate the database:
1
2

rake db:migrate
Now we need to modify our models to set up the associations.
1
2
3
4
5
6
7
8

class Genre < ActiveRecord::Base
  has_many :artists
  has_many :songs, :through => :artists
end
class Artist < ActiveRecord::Base
  has_many :songs
end
That should be it, now let's go to the console and see that all this works:
1
2
3
4
5
6
7
8
9
10

ruby script/console 
Loading development environment (Rails 2.0.2)
>> g = Genre.find(:first)
=> #<Genre id: 1, name: "Genre 1", created_at: "2008-03-30 11:52:25", updated_at: "2008-03-30 11:52:25">
>> g.artists
=> [#<Artist id: 1, name: "Artist 1", genre_id: 1, created_at: "2008-03-30 11:52:25", updated_at: "2008-03-30 11:52:25">, #<Artist id: 2, name: "Artist 2", genre_id: 1, created_at: "2008-03-30 11:52:25", updated_at: "2008-03-30 11:52:25">]
>> g.songs
=> [#<Song id: 1, title: "Song 1", artist_id: 1, created_at: "2008-03-30 11:52:25", updated_at: "2008-03-30 11:52:25">, #<Song id: 2, title: "Song 2", artist_id: 1, created_at: "2008-03-30 11:52:25", updated_at: "2008-03-30 11:52:25">, #<Song id: 3, title: "Song 3", artist_id: 2, created_at: "2008-03-30 11:52:25", updated_at: "2008-03-30 11:52:25">, #<Song id: 4, title: "Song 4", artist_id: 2, created_at: "2008-03-30 11:52:25", updated_at: "2008-03-30 11:52:25">]
>> 
Looks like it works :) Ok, now on to the controller. Our controller needs to have some action for the view, I just used index, and two other actions, for remote function calls, I called these update_artists and update_songs. update_artists() is called when a genre is changed and it updates the list of artists and the list of songs based on the genre. update_songs() only updates the songs based on the artist. So let's look at this code:
# the controller
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

class TestItController < ApplicationController
  def index
    @genres  = Genre.find(:all)
    @artists = Artist.find(:all)
    @songs   = Song.find(:all)
  end

  def update_artists
    # updates artists and songs based on genre selected
    genre = Genre.find(params[:genre_id])
    artists = genre.artists
    songs   = genre.songs

    render :update do |page|
      page.replace_html 'artists', :partial => 'artists', :object => artists
      page.replace_html 'songs',   :partial => 'songs',   :object => songs
    end
  end

  def update_songs
    # updates songs based on artist selected
    artist = Artist.find(params[:artist_id])
    songs  = artist.songs

    render :update do |page|
      page.replace_html 'songs', :partial => 'songs', :object => songs
    end
  end
end
Now as far as views go we have one view (index.html.erb) and two partials (_songs and _artists). Let's take a look at those:
# the _songs partial (_songs.html.erb):
1
2
3

<%= collection_select(nil, :song_id, songs, :id, :title,
                     {:prompt   => "Select a Song"}) %>
# the _artists partial (_artists.html.erb):
1
2
3
4
5
6

<%= collection_select(nil, :artist_id, artists, :id, :name,
                     {:prompt   => "Select an Artist"},
                     {:onchange => "#{remote_function(:url  => {:action => "update_songs"},
                                                      :with => "'artist_id='+value")}"}) %>
<br/>
# and last, but not least, the index view (index.html.erb):
1
2
3
4
5
6
7
8
9

<%= javascript_include_tag :defaults %>
<%= collection_select(nil, :genre_id,  @genres,  :id, :name,
                      {:prompt   => "Select a Genre"},
                      {:onchange => "#{remote_function(:url  => {:action => "update_artists"},
                                                       :with => "'genre_id='+value")}"}) %>
<br/>
<div id="artists"><%= render :partial => 'artists', :object => @artists %></div>
<div id="songs"><%= render :partial => 'songs',   :object => @songs %></div>
Ok, this probably takes some explanation. I will save that for part II, where I will also improve upon what we have so far and include a demo.

For now, if you have any questions, just ask me in the comments.

Changes/Fixes to the Simple CMS Plugin

February 28th, 2008 by slaive

You can also click here for the tutorial. Or you can click here to check out the demo.

We are continuously adding to and changing the Simple CMS Plugin so here is a little rundown of what has been changed so far:

Major Changes:

  • I have updated to rails 2.0.2 so if you are using an older version you will need to change a line in each of the controllers.
  • 1
    2
    3
    4
    5
    6
    
    
    # Where it has:
      self.view_paths << File.join(File.dirname(__FILE__), '..', 'views')
    # Must be Changed to:
      self.template_root = File.join(File.dirname(__FILE__), '..', 'views')
    
    
  • The acts_as_versioned plugin is now required for the revisions. I added this quite some time ago. I did change the rake task to install this plugin as well as the rest.
  • You now have to pass a :prefix if you have one. This is to ensure that all content such as images, media, smiles, etc. work correctly. If your base path is a standard path then you do not need to worry about this.
    For example: I was running 3 rails applications under one domain so it looked like this:
    my.domain.com /blog
    /forum
    /demo
    So I would call my Simple CMS content like this for blog:
  • 1
    2
    3
    
    
    <%= render :simpleCMS => "MyBlog", :admin => true, :prefix => "/blog" %>
    
    
  • Now you can make content viewable and editable from multiple pages by passing :reusable => true. This defaults to false. Your label must be the same in each place you use it. This is very useful for layouts, such as header and footer.
    *NOTE* If you already have content here and you change this variable you will lose all that content as it gives the content a new id and changes the params and how the content is called. For example if I have :reusable set to false and I have content there and I set :reusable to true then it creates content with a different id so I will not be able to use the old content until I change it back to false.

Minor Changes:

  • When you click on a revision you are taken back up to the top of the page instead of having to scroll all the way down a list of 100 revisions, clicking on one, and then manually scrolling all the way back up to the top to see if you even picked the right revision
  • I have added code highlighting and this requires the coderay plugin, which has been added to the rake simple_cms:install_dependencies, and a coderay stylesheet so you need to add that to your application layout. I have included it in the rake simple_cms:install
  • 1
    2
    3
    
    
    <%= stylesheet_link_tag "coderay" %>
    
    
  • I have also changed many things in the javascripts inside the tiny_mce editor so it would be safest just to use the rake tasks that are built in:
  • 1
    2
    3
    4
    
    
    rake simple_cms:uninstall
    rake simple_cms:install
    
    

I have updated the tutorial with all the changes as well.

There is also a demo that you can use to play around with it and ask questions.

Errno::EINVAL - Invalid argument

February 19th, 2008 by charlie

Windows' servers are pretty much an awful nightmare to get working. A company that I am doing work for had the bright idea of hosting a fairly major web application on windows. Not a good idea, not a good idea at all. This has caused nothing but problems from ferret to having no way of stopping a service to this error - Errno::EINVAL - Invalid argument.
The typical error you get looks something like this:

Errno::EINVAL in .....

Invalid argument
....
.../lib/active_record/base.rb:1358:in `write'
.../lib/active_record/base.rb:1358:in `compute_type'
....

Ya, that is not something you want to get and have no idea what is going on, not to mention that it only happens every once in a while. Especially, when you are already frustrated because nothing else seems to work perfectly.

The error is caused when you are using a windows server and have decided that, as a good windows' administrator, you will create a mongrel service for your application and set it to start automatically. The service knows nothing about STDOUT, so anything written to STDOUT will produce the error above. But, what still baffles me is the complete and utter randomness of the whole situation. Why does it not happen all the time, why only every 6 to 10 times that I hit the same exact page? Well, I can't help you there, but let me know if you have figured it out.

So, if you are lucky enough to get the same error above, then I have a solution for you, well actually a couple solutions. First, if you have the choice, ditch windows, not worth it. However, if you are like me and are forced to use windows for a project then your solution is a simple derivative of what you will find here.
None of those solutions worked for me, or at least not to the point where I was satisfied. They all got me very close, but without a way of still logging STDOUT. The closest and, as the link above points out, the safest was to redirect STDOUT to a logfile:
1
2

STDOUT.reopen(...)
Well, that, unfortunately, did not work for me for some reason, probably some fault of windows, I am sure. If you get it working, stick with that solution. Otherwise, I went with the following:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

###################################
# RAILS_ROOT/lib/std_out_logger
###################################
class StdOutLogger
  def write(s)
    f = File.open("log/stdout.log", "w+")
    f.puts s.inspect
    f.close
  end
end
###################################
# RAILS_ROOT/app/controllers/application.rb
###################################
# redirect the output to a log file for when we run as a service
before_filter {
  $stdout = $stderr = StdOutLogger.new
}

I hope that helps you, it worked for me. Good luck.

Open Flash Chart Plugin for Ruby on Rails

February 4th, 2008 by charlie

I just finished converting version 1.9.7 of Open Flash Chart over to ruby, for use with rails.
Check out what I can do now :) I can customize my tooltips:

Extra Tool Tips



View Source Code


More examples can be found on my Open Flash Chart Projects page.
Don't forget to check out the original - http://teethgrinder.co.uk/open-flash-chart/.

Simple CMS Plugin for Rails - with revisions

February 2nd, 2008 by charlie

Well, we have been working on SimpleCMS a little and just for kicks we added revisions.
Check out the Simple CMS Plugin Demo
On this page you will see the "Show all revisions" link at the bottom of the "edit" page.
So feel free to add or delete or change revisions at will.
Also, if you are new to SimpleCMS, check out the sort of rough getting stared page.
Well, enjoy and please leave comments/feedback/requests here in the comments or preferably in the list of requests we have started on the demo page :)

Rounding to the nearest number in Ruby

January 31st, 2008 by charlie

A while ago, I was taking a look at a problem on the rails forum. This post was submitted to find the best solution to round any number to the nearest multiple of 10. For example, this method would take the number 6 and return 10, or the number 29 and return 30. So the first thing that popped into my mind was modulus. We can use modulus to determine how far we are from the nearest multiple of 10. Meaning that if we are given 19 and we want to know how close we are to the nearest 10, we can simple do 19 % 10, which will return 9, and 10 - 9 is 1, so we are 1 away from the nearest 10 spot. Here is that method, assuming only Fixnum, so it is implemented as an extension of the Fixnum class:
1
2
3
4
5
6
7
8

class Fixnum
  def roundup
    return self if self % 10 == 0   # already a factor of 10
    return self + 10 - (self % 10)  # go to nearest factor 10
  end
end 

While this did the job, it was suggested that it would be better if things happened.
  1. Use the Numeric class (this class encompasses Float, Fixnum and Integer)
  2. Don't limit the method to just the nearest 10, have it as a parameter
  3. And an added bonus - rounddown()

Here is the resulting code (defaulting to 10):
1
2
3
4
5
6
7
8
9
10

class Numeric
  def roundup(nearest=10)
    self % nearest == 0 ? self : self + nearest - (self % nearest)
  end
  def rounddown(nearest=10)
    self % nearest == 0 ? self : self - (self % nearest)
  end
end 

Well that is pretty cool, here is some sample output from using this method:
1
2
3
4
5
6
7
8
9

puts 2.roundup    #=> 10
puts 23.roundup   #=> 30
puts 20.roundup   #=> 20
puts 45.roundup   #=> 50
puts 156.roundup  #=> 160 
puts 156.34.roundup   #=> 160.0
puts 16.34.roundup    #=> 20.0
puts 81.1234.roundup  #=> 90.0 

Convert a Ruby hash into a class object

January 5th, 2008 by charlie

I first saw the need to convert a hash object to a class when answering this post.
In the post, the user wanted to load a YAML object into his hash and then present the data from the hash in a form. Needless to say it was not very DRY the way it had to be implemented. So I started looking into it, I found this. This solution was a great starting point for where I ended up, but it was not general enough, it was hard coded, plus it was missing the getters and setters. So it turns out that in ruby it wasn't too much trouble to convert a hash into a class object. So let's get started:
I have implemented this for use in Rails, so let's start with the model that does all the magic:
1
2
3
4
5
6
7
8
9
10
11

class Hashit
  def initialize(hash)
    hash.each do |k,v|
      self.instance_variable_set("@#{k}", v)  ## create and initialize an instance variable for this key/value pair
      self.class.send(:define_method, k, proc{self.instance_variable_get("@#{k}")})  ## create the getter that returns the instance variable
      self.class.send(:define_method, "#{k}=", proc{|v| self.instance_variable_set("@#{k}", v)})  ## create the setter that sets the instance variable
    end
  end
end

Notice the self.class.send(:define_method ...) rather than self.define_method, this is a hack to overcome the fact that define_method() is private. I had come across this when trying to figure out the post mentioned above. Found the information to solve this here.
Ok, so on to the Controller that creates the Hashit object:
1
2
3
4
5
6
7
8
9

class TestItController < ApplicationController
  def index
    hashit = {:support_email  => "test@test.com",
              :allow_comments => 0}
    @hashit  = Hashit.new(hashit)
  end
end

Well that is easy, pass in a hash and get an object. Here is what @hashit looks like at this point:
1
2

#<Hashit:0xb6a65110 @allow_comments=0, @support_email="test@test.com">
And of course, now the view, what we wanted to clean up and make more elegant. Here is what the user started with:
Note: In this example @hashit is an actual hash, not a class object.
1
2
3
4
5
6

<% form_tag :action => 'config', :method => :post do %>
  <%= text_field 'settings',  'support_email', :size => 20, :value => @hashish['support_email']%>
  ...
<% end %>

And here is what our view code looks like now:
1
2
3
4
5

<% form_for :hashit, :url => {:action => 'index'} do |f| %>
  <%= f.text_field :support_email %>
<% end %>

Much simpler, DRYer :)
Well that is pretty much it, I suppose the next step would be to have a save method that updates the hash? This way we can do @hashit.save() and it will return a new hash that you can use. Well actually, that probably isn't too hard, lets see if I can do it real quick, class object back to hash ...
Well, I am back and I was able to figure it out, here is the new class:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

class Hashit
  def initialize(hash)
    hash.each do |k,v|
      self.instance_variable_set("@#{k}", v)
      self.class.send(:define_method, k, proc{self.instance_variable_get("@#{k}")})
      self.class.send(:define_method, "#{k}=", proc{|v| self.instance_variable_set("@#{k}", v)})
    end
  end

  def save
    hash_to_return = {}
    self.instance_variables.each do |var|
      hash_to_return[var.gsub("@","")] = self.instance_variable_get(var)
    end
    return hash_to_return
  end
end

Just added the save() method, that takes all the instance variables and sets them as keys in our new hash. So here is the outcome of our save():
1
2

{"support_email"=>"new@some_email", "allow_comments"=>0}

OpenGL in the browser

January 5th, 2008 by charlie

Neat, this is just from the examples, more to come with opengl when I get a chance.
Check out this guy's opengl stuff, really cool!
This requires java applet support, and I can say that it works wonderfully in Linux/FireFox, and Alias (from above) says that it works with IE. So there you have it.


Use your mouse and move it around ....

This browser does not have a Java Plug-in.
Get the latest Java Plug-in here.

Built with Processing

Open Flash Chart Plugin for Ruby on Rails

January 3rd, 2008 by charlie

I just finished converting the latest version of Open Flash Chart over to ruby, for use with rails.
Check out what I can do now :) Like the google analytics graphs.

Scatter Chart



View Source Code


More examples can be found on my Open Flash Chart Projects page.
Don't forget to check out the original - http://teethgrinder.co.uk/open-flash-chart/.