Tropical Software Observations

Showing posts with label ruby. Show all posts
Showing posts with label ruby. Show all posts
22 September 2010

Posted by Yasith Fernando

at 5:03 PM

1 comments

Labels: , ,

Evaluating Redcar

Intro and Background

It has been about 2 weeks since I started developing RoR and Ruby apps in general at Favorite Medium. When I got started I had an OS X environment that I was new to and Textmate as my editor. I choose Textmate because (let's be honest...) it seems to be very popular with rails developers. But I had already used and developed in ruby using IDEs such as NetBeans and Rubymine. And I still tend to prefer an IDE over a text editor.

However, now I feel more comfortable with Textmate as I have used it for over two weeks. I will be evaluating Redcar and will be comparing it (well yes, my attitude towards Redcar is that it is really inspired by Textmate) with the experience I had with Textmate. To be fair, I haven't used Textmate extensively and I am for sure missing out on some great features it may have. So forgive me if I make any inaccurate assumptions in this post.

I am doing this evaluation as a ruby developer. So developers of other languages might look at this editor under a different light.

What is Redcar

Redcar is a free and open source text editor written in ruby (but runs on jruby. You don't need to have jruby installed in order to install Redcar though. It will auto-magically download a version of jruby and other needed libs for its use). It has a Textmate-like feel to it. It also supports Textmate bundles (one of the strong points of Textmate)! Right now it has an active, healthy community around it. But it's a very young project that is still under heavy development (ex:- it doesn't have a save all function :( ).

Let's break it down to pros and cons.

Pros

  • It's Open Source (thus free as in free beer and freedom!)

  • Has a good momentum behind it (at the time of this writing).

  • Supports Textmate bundles (This means a lot. If you have used Textmate you would know that a lot of nice features of Textmate come through bundles) and themes.

  • Written in pure ruby and runs on jruby (this is good news if you are a ruby developer - it will be easy to extend and write plugins in ruby).

  • Cross platform (I think I know more than 10 people who wanted to find 'the Textmate for Linux/Windows').

  • Extensible (no editor in this world will ever behave and do everything just like you would want it to. You will have to customize it at some point. And the author can't implement every feature under the sun. A good plugin system is very important).

  • Easy learning curve if you are coming from Textmate (Redcar supports most Textmate shortcuts although it's not a one to one mapping. It also has a lot of functionality that can be found in Textmate, where they are identified by the same names).

  • Last but not least, Redcar comes with the 'cool-latest-greatest' feeling attached. So you can always feel good using and hacking it.

Cons

  • Uncertainty about future support and longevity of the project (Redcar is great. And it's very promising. But we don't know where it will stand in another two years. Editors are things that people choose, learn, and live with. If I am to commit my self to an editor I need to be sure that it will be supported and actively developed for the near future. If the development stalls I can't afford to take it over and carry it on. But then Redcar is so similar to Textmate, so in the event of Redcar suffering a early death one could always go back to Textmate or to one of its many clones out there.)

  • Lack of features – For its age Redcar definitely supports a ton of features! But if you want a full and complete product Redcar is not that (at least at the time of writing it's not. But I hope it will be able to come to that level in the near future). But with the active development community and the passion behind it. I hope that it can reach a level where it has a healthy set of complete features pretty soon.

  • Lack of maturity – You will see it in the UI sometimes, and everywhere else. This is perfectly natural for a new project.

    Requirement of Java - I am not sure whether this is even a con. But some people might not feel very comfortable having to install java if they don't already have it (you already have Java pre-installed in OS X for example...).

All in all I feel I will give this a try and see how things go. I have just gone through the documentation and installed and used Redcar for like 2 hours. You can't tell what's working and what's not during such a small amount of time. Issues with stability and performance might pop up during prolonged usage. But I have a positive outlook about this. There is an upcoming rails project and I am going to use Redcar for it. Let's see how things go.


If you are excited by new tech and if you are in to ruby/rails and Textmate definitely do check out this new editor. Its worth the while.

27 August 2010

Posted by Isak Rickyanto

at 12:37 PM

5 comments

Labels: , , ,

Initial Thoughts on Padrino, a Fast Ruby Web Framework Based On Sinatra

In search of a Rails alternative in the Ruby world, I found a popular and simple web framework, Sinatra, that was introduced to me by a friend. It is very easy to get started with Sinatra, especially for a simple Hello World kind of web app.

But based on my experience with Rails, Grails, and CakePHP, all web frameworks that help us develop easier and faster with their features, helpers, and also lots of plugins, I admit that I was not that interested in using Sinatra in a real project.

I like Sinatra's simple and minimal concepts, but in the real world we sometimes need more than that. So, although I believe I can build any kind of web application with Sinatra, I feel that sooner or later I will look for helpers, utilities, or plugins that can help me in development.

Then I found Padrino, also introduced to me by my friend, which is a bigger and richer framework than Sinatra in term of features and helpers. It seems like a complete framework but still sticks to Sinatra's core concepts and philosophy, since the developer built this framework as a layer on top of Sinatra while trying to keep it fun and easy. You can find Padrino here: www.padrinorb.com

The things I like best about Padrino:

1. Code Generator - easily generates beautiful admin interfaces with built in authentication.
2. Agnostic Way - gives us options to choose what module or library we want to use, like letting us choose between Active Record, Datamapper, or Sequel for ORM.
3. Fast Performance - Padrino's performance benchmark shows us it is faster than Sinatra itself, which sounds impossible right?

Benchmarks for Padrino vs Merb vs Rails vs Sinatra vs Ramaze:

# Rendering a string inline
Merb 1.1.0 => 1749.97 rps
Padrino 0.9.10 => 1629.15 rps
Sinatra 1.0.0 => 1537.78 rps
Rails 3.beta3 => 381.76 rps
Ramaze 2010.04.04 => 270.08 rps

# Rendering a basic erb template
Merb 1.1.0 => 1490.8 rps
Padrino 0.9.10 => 1416.84 rps
Sinatra 1.0.0 => 1157.89 rps
Rails 3.0.beta3 => 330.58 rps
Ramaze 2010.04.04 => 254.23 rps

# Rendering a simulated simple app
Padrino 0.9.10 => 675.79 rps
Sinatra 1.0.0 => 652.0 rps
Merb 1.1.0 => 642.29 rps
Rails 3.0.beta3 => 201.86 rps
Ramaze 2010.04.04 => 130.62 rps

(copied from http://www.padrinorb.com/blog/padrino-0-9-10-released-built-for-speed)
Get the source code for benchmark from http://github.com/DAddYE/web-frameworks-benchmark

4. Comprehensive Features - Padrino provides us with a lot of features, helpers and libraries that aid us in web development

5. Great Support for Shiny Things like HAML, SAAS, MongoDB

Along with these advantages, I also found some things that need to be improved:

1. Small Community - I hope it will get better in the future (Padrino's Google group only has 122 members). Perhaps it needs more “marketing” to attract newcomers. Open source projects gain trust more easily if they have large and active communities.

2. User Guides - Padrino needs more comprehensive and complete tutorials. For example, if a new user comes to the Padrino site without existing Active Record, Datamapper, or other compatible ORM experience, I believe they will be confused because the documentation does not include those ORMs. I only found a simple active record example in a blog tutorial. I admit there are many external examples covering documentation of these ORMs, but the information is not directly linked/integrated with Padrino. From my experience, I ran into difficulty when trying to build an HTML form with HABTM relation, and it was difficult to find any relevant information about the problem as related to Padrino. Fortunately I had experience with Active Record so finally after struggling for a few hours I found a solution but this might not be the case with someone new to web development and experiencing it for the first time using Padrino.

3. Sample Project, Real Live Projects still rare
In learning, it is easier for me as newcomer to learn from examples so it will be great to see a few sample projects, something more than just a simple blog app. Also I still can't find a list of real live production sites or projects using Padrino. I found only 1-2 sites that use Padrino (1 shopping project and watched.it). There may be many more than that number who already use Padrino, but this information is not well documented. If you are interested, here is a discussion about who is already using Padrino:
http://groups.google.com/group/padrino/browse_thread/thread/d439332aa95227e3/4265f4a2cad796c7

Conclusion:
I believe that if the people behind Padrino keep doing a good job with developing and promoting Padrino, and also take care their community, Padrino will become a great web framework, maybe a better alternative than Rails. If you have experience with Rails and Sinatra, it will a be friendly framework for you to work with.

I would confidently use Padrino for simple applications but personally I feel it will be risky to build a serious application using an open source project without knowing there is more significant community support behind it (please note: I am not saying the Padrino community is not welcoming or responsive).

26 January 2010

Posted by Kamal Fariz

at 6:16 PM

1 comments

Labels: , , , ,

Full-text search in Rails with Sunspot

There comes a time in every app when doing a “SQL LIKE” query just doesn’t cut it. I’m going to show you how easy it is to add proper full-text search to your Rails app using the Sunspot::Rails plugin.

Sunspot

Sunspot is a standalone Ruby library that makes integrating with a Solr search engine a cinch. It wraps all the nitty gritty of indexing and querying in a declarative DSL which you can use to expose virtually any Ruby object to be searched, not just ActiveRecord models. The sunspot gem bundles a standalone Solr search engine (mostly stock, served by Jetty, although also contains support for geolocational ordering).

Sunspot::Rails is Rails plugin which is basically Sunspot the library plus some hooks into ActiveRecord to update indexes on creates and updates as well as the Rails request lifecycle commit the index at the end of every request. It adds the DSL as class methods into ActiveRecord to allow you to configure the index much like in the style of configuring association or named_scopes. The gem also bundles a set of rake tasks to manage starting, stopping and restarting the Solr service.

Installation

  1. Install the gem
    $ gem install sunspot_rails
  2. Edit your config/environment.rb to include
    config.gem 'sunspot', :lib => 'sunspot'
    config.gem 'sunspot_rails', :lib => 'sunspot/rails'
  3. Generate the sunspot configuration file in config/sunspot.yml
    $ ./script/generate sunspot
  4. Run the Solr service
    $ rake sunspot:solr:start
    (if Rake complains that it couldn’t find this task, add require 'sunspot/rails/tasks' to the top of your Rakefile).

Defining an Index

The first thing you need to do before anything can be searched is creating an index. There is two parts to this.

The first part is defining an index. For Rails models, you can define it using the searchable class method. Suppose we have an Article that belongs to an Author.
class Article < ActiveRecord::Base
belongs_to :author

searchable do
text :title, :boost => 2.0
text :body
text :author_name do
author.name
end
time :updated_at # for sorting by recent
string :sort_title do # for sorting by title, ignoring leading A/An/The
title.downcase.gsub(/^(an?|the)/, '')
end
boolean :published, :using => :published?
end

def published?
state == :published
end
end
Sunspot supports text, string, time, boolean, integer and float fields. When planning what to index, note that only text fields are exposed as full-text search while the other field types are used for restricting, sorting and faceting.

What I like about the DSL is the flexibility. You can directly index an ActiveRecord attribute (:title, :body) or virtual attributes by giving it a block (:sort_title) or a symbol to a method (:published). Even indexing associations is really a matter of calling methods on it.

The second part is indexing. Sunspot provides a utility method to reindex all records for a particular class. In our example, we can call

Article.reindex!

and have the entire Article index rebuilt. For finer grained indexing, you can call Article#index! on a particular instance. As mentioned above, if you are creating and updating models via controllers as in a typical Rails app, this should all be transparent to you.

Querying

Sunspot provides a flexible DSL for querying. A SearchController might look something like this
class SearchController < ApplicationController
def show
@search = search(params)
end

protected
def search(options)
Sunspot.search(Article) do
keywords options[:query]
with(:published, true)
order_by :updated_at, :desc
paginate :page => options[:page]
end
end
end
keywords will be applied to all text fields. The remaining non-text fields can be defined to restrict the query (in the example, we want restrict it to published Articles) and ordering (in the example, we ordered by updated_at). If you don’t define an ordering, the results will be returned sorted by relevance based on occurence and location of the keywords in the document and the index as a whole. You can tweak the relevance score by defining boosts — in this example, Article titles that match the keywords are given a boost over other Articles that may match the keyword elsewhere.

You can define multiple restrictions and they don’t always have to be for equality. It supports restricting by a value being less-than, greater-than, between, any or all (when comparing for an indexed array). The restrictor with(:published, true) is simply a short-hand for with(:published).equal_to(true). You can also test the absense of a value using the without operator.

Finally, Sunspot plays nice with the WillPaginate plugin. In your view, you can paginate easily by doing
<%= will_paginate @search.results %>
and expect it to work seamlessly.

Conclusion

That’s all there is to it to get up and running with Sunspot. My take-home point is Sunspot exposes extremely flexible DSLs that allow you to scale from simple to pretty complicated queries with ease.

If this interested you, you may want to check out the wiki for other features not covered by this article including highlighting of keywords, facets and stored fields.

20 March 2009

Posted by Unknown

at 9:40 AM

0 comments

Labels: ,

Grails and Rails: Domain Classes and Web Services

Let's take a brief look at the differences between Grails and Rails in term of persisting domain classes and creating web services. Both Grails and Rails are MVC frameworks and are very similar in terms of code syntax.

1. Domain Class Persistence

In Grails:



class Person {
String firstName
String lastName
String email
Date birthDate
Address address

static constraint = {
firstName(blank:false)
lastName(blank:false)
email(blank:false, email:true) // check if it's really e-mail
}
}

class Address {
String street
String city
String country
Person person

static belongsTo = Person
}



In Rails, attributes can be inferred from the database table's structure:

class Person <>
# Expects database schema to have a table "person"
# with columns first_name, last_name, email, birth_date

validates_presence_of :first_name, :last_name, :email
end

class Address <> has_one :address
belongs_to :person
end


2. Making a service class available as a web service

In Grails, inside a controller closure:


def listAllPeople = {
def pplList = Person.list() // or by query Person.findByLastName("Hewitts")
render pplList as XML
// render pplList as JSON
}



In Rails, inside a controller block:


def listAllPeople
@pplList = Person.all # or by query Person.find_by_last_name("Hewitts")
render :xml => @pplList
# render :json => pplList
end


Note:
1. Grails will auto-generate the database schema and update the schema when more domain fields are added to the class. It's also possible to go in the reverse direction if you prefer starting with an existing schema.
2. Rails expects the database schema to be pre-created and to conform to camel case naming conventions.
3. Grails has the notion of service classes which are commonly used for business logic and can be use in a controller as a web service end point.

24 August 2006

Posted by Bacchus D

at 4:44 AM

1 comments

Labels:

Object Creation In Ruby

Please bear with me as I stumble through 'Programming Ruby'. Today's topic is object creation.

Here's a very simple Ruby class. Its three attributes are all initialized in the constructor, aptly named initialize(). Each attribute has a public accessor and mutator granted by the attr_reader and attr_writer keywords, respectively. It's worth pointing out here that methods are public by default, though access can be tightly controlled as I'll show later.


class Song

attr_reader :name, :artist, :duration
attr_writer :name, :artist, :duration

def initialize(name, artist, duration)
@name = name
@artist = artist
@duration = duration
end

def to_s # instance method
"#{@artist} - #{@name} (#{@duration})"
end

def self.clone(s) # class method
newSong = Song.new(s.name, s.artist, s.duration)
return newSong
end

end

Creating an instance of this class is simple:

s1 = Song.new("All Things To All Men", "Cinematic Orchestra", 290)

However, the following invocation results in a "private method `initialize' called for #Song:0x100f3f88 (NoMethodError)" error:

s2 = s1.initialize("Seeing Red", "Minor Threat", 125)

There are a couple of interesting things to note here. First off, even though we didn't scope initialize() as private, apparently it is anyway. More interesting, though, is that we instantiate objects using the class method new() provided in the base class Object and not through the use of a global operator as in languages like C++. While initialize() plays an important role in object creation, it doesn't tell the whole story. The class method Song.new() allocates memory for a new, uninitialized object. It then invokes the new object's initialize() method, passing along the arguments from the original call to new(). In contrast to languages like Java that treat memory allocation and initialization of objects atomically, Ruby allows the programmer to handle these operations discretely by overriding Class.new(). It might help to think of new() as a built-in factory method inherited from the base class. Here's a pared down version of our Song class that illustrates how you might use this strategy to limit object creation by performing lookups against a cache.

class Song

attr_reader :name, :artist, :duration

def initialize name, artist, duration
@name = name
@artist = artist
@duration = duration
end

def self.new *args
# check cache first
obj = CacheManager.lookup args[0]

# if cache miss, then create new song
if obj == nil
newObj = self.allocate
newObj.send :initialize, *args
return newObj
end

# we have a hit, just return it
obj
end

end

Minus the cache bit this example was basically lifted straight out of Programming Ruby. Instead of blindly creating an object every time Song.new() gets called, we first check the cache to see if an object with the same key already exists. If so we simply return the cache hit, otherwise we reimplement Object.new(), allocating memory for a generic object, then invoking Song#initialize() by passing its symbol to Song#send() (once again inherited from base class Object).

References

Thomas, D. and Hunt, A. "Programming in Ruby." Dr. Dobb's Journal. 2001. http://www.ddj.com/184404436

"Ruby 1.8.4 Documentation." Ruby-Doc.org. 2006. http://www.ruby-doc.org/core/

Thomas, Dave. Programming Ruby. 2005. The Pragmatic Bookshelf.