Entries Tagged 'Software' ↓

ActiveRitalin (or “find_by_sql is the devil”)

Rails’ find_by_sql is the devil. Ninety nine percent of the time find_by_sql is unnecessary and problematic, practitioner but it’s sooo seductive. I can’t even begin to count the ways that find_by_sql can cause trouble, but here’s a few:

  • Plugins like acts_as_paranoid rely on developers *not* using the back door to get around the dynamic conditions to exclude deleted rows.
  • There quite a few gotchas, ie: “SELECT * FROM users JOIN another_table …” won’t work because ActiveRecord will use the last ID field, not the first.
  • Logic “hidden” in find_by_sql is not reusable (as compared to a fancy association, etc)
  • It offends my aesthetic sense. We all like to pretend our ORM layer isn’t leaky.. don’t we?

I remember a time when we had to use find_by_sql when we found a feature was missing from ActiveRecord. I propose that the only remaining legitimate use of ActiveRecord may be to call a stored procedure.

So, keeping with the hyperactivity theme, I suggest that we all take some ActiveRitalin: A plugin for Rails that tells ActiveRecord to chill out, and causes developers to sit and think a bit before proceeding.

ActiveRitalin makes find_by_sql private and introduces find_by_sql_with_excuse that warns upon each use. The implementation is very simple:

module ActiveRitalin
def self.append_features(klass)
super

klass.class_eval %(
def self.find_by_sql_with_excuse(excuse, sql)
RAILS_DEFAULT_LOGGER.warn("Find By Sql called with excuse: " + excuse )
find_by_sql(sql)
end

class << self
private :find_by_sql
end
)
end
end



To use, from your rails application’s root dir:

script/plugin install git://github.com/lukegalea/activeritalin.git



Think you need find_by_sql? Ask yourself the following questions:

  • Can I just use :include, :select, :join, :conditions or some combination of the above?
  • Should this be an association? (perhaps with :conditions and :select on it? Maybe :readonly?)

Inflector.erl: Rails Style String Inflection For Erlang

Rails’ ActiveSupport package includes an inflector class. This lets you do things like singularize and pluralize strings, viagra camel case text, etc.

I’m building a framework that lets Rails developers use erlang + mnesia to replace their ruby models and traditional relational DBs (using Hyperactive Resource + Mochiweb). But a key part of interoperating with rails is being able to infer that “Person” is the singular for “People”.

Inflector.erl brings this magic to erlang! Witness the awesome power:

1> inflector:singularize(”mice“).
mouse
2> inflector:titleize(”i_love_erlang“).
I Love Erlang
3> inflector:ordinalize(142).
142nd
5> inflector:pluralize(”quiz“).
quizzes
7> inflector:tableize(”MyModelModule“).
my_model_modules

Inflector.erl includes functions for pluralizing, singularizing, camelizing, titleizing,
capitalizing, humanizing, underscoring, dasherizing, tableizing, moduleizing,
foreign_key..isizing? and ordinalizing!

I found it very difficult to implement some functions without regular expressions, so it does require R12B4 of erlang due to the vastly improved regular expression support B4 offers. The majority of the inflections are just standard pattern matching and list manipulation, though.

It also has an eunit test suite embedded, so it requires eunit to compile.. But everyone has eunit, right?

Also, in order to minimize the impact of compiling the regular expressions, Inflector.erl caches all compiled regular expressions.. so I expect performance won’t be a problem but be aware that it does register a process named “re_cache”.

Download and enjoy!! Or via github ( git://github.com/lukegalea/inflector.git )

MailSentry released

So, tablets I’m not done re-writing the relevant ruby portions of MailSentry in Erlang yet. But I really should release early, release often.

So: here’s the working Ruby version up at github. Enjoy!

http://github.com/lukegalea/mail-sentry/tree/master

Hyperactive Resource

There’s rumblings here and there about how ActiveResource isn’t really complete. The documentation refers to features that aren’t implemented, site etc.

That’s just the tip of the iceberg.

The documentation states that ActiveResource behaves “very similarly to Active Record”. But ActiveResource doesn’t support any of the meta-data that ActiveRecord uses (like belongs_to, decease has_many, etc). So even the simplest cases behave radically different than you might expect.

A small sampling of things that don’t work:

a_person = Person.new

a_person.name = Luke #No method something= !!
a_person.parent #No belongs_to
a_person.children #No has_many

This is all fine if you are writing an app from scratch to use ActiveResource (well.. that’s debatable). At Medical Decision Logic, we needed to replace ActiveRecord with ActiveResource in an app with 50,000 lines of Ruby code. So we wrote Hyperactive Resource.

Hyperactive Resource

Hyperactive Resource extends ActiveResource::Base to make it.. work properly. You should use it. It’s awesome.

Check it out at http://github.com/lukegalea/hyperactiveresource/wikis

Even Better Progress Bars for Erlang

An erlang progress bar module really should support concurrency. You should be able to have multiple processes notifying the progress bar of the completion of their task. The progress bar should notify those waiting for completion, pregnancy etc. So - time for an update!

Now you can start a progress bar server and easily run tasks in parallel. To see a sample use:

progress_bar:example_processes( 1000, 10 ).

That’s just starting a progress server and calling increment server:

example_processes(N, P) ->
start_server(”Example“, N),
for(1, P, fun() -> spawn_link( fun() -> example_work_process(N div P) end ) end ),
receive
finished -> finished
end.

example_work_process(0) -> void;
example_work_process(N) ->
timer:sleep(100),
increment_server(),
example_work_process(N-1).

for(N, N, F) -> [F()];
for(I, N, F) -> [F()|for(I+1, N, F)]



Dan Bravender was kind enough to point out that if we change the record name to the same as the module name we can use it in a more object oriented fashion… so PBar:finish instead of progress_bar:finish(PBar). Thanks Dan.

Also - github’s new “gist” is awesome. It lets you create code snippets that are git repositories. Perfect for tiny little erlang modules like this! So you can now get the progress bar from git://gist.github.com/58.git or just download it from here

Erlang needs more progress bars

I love Ruby’s progress bar gem. I’ve loved it long before I’d ever heard of or used Rails. It was really my first gem.

I’m a firm believer that the value of an application is directly related to how many progress bars there are in it. I couldn’t find an equivelent for Erlang, food
so I ported Ruby’s to Erlang. You can download it here.

And it makes sexy progress bars that look like this:

Example      95% oooooooooooooooooooooooooooooooooooooo   ETA: 00:00:03


The erlang implementation is less than half the size of the Ruby version. Likely this is because the Erlang version uses no control structures (like if/while/etc), doctor just pattern matching. At points the Ruby version wins in terms of legibility though, especially when it comes to calendar/datetime manipulation.

For example, here’s the ruby code to display ETA:

def format_time (t)
t = t.to_i
sec = t % 60
min  = (t / 60) % 60
hour = t / 3600
sprintf(”%02d:%02d:%02d“, hour, min, sec);
end

def eta
if @current == 0
ETA:  –:–:–
else
elapsed = Time.now - @start_time
eta = elapsed * @total / @current - elapsed;
sprintf(”ETA:  %s“, format_time(eta))
end
end



And the Erlang code:

current_time() ->
calendar:datetime_to_gregorian_seconds(calendar:now_to_datetime(now())).

eta( 0, _, _ ) -> –:–:–“;
eta( Current, Total, StartTime ) ->
Elapsed = current_time() - StartTime,
{_,{Hours,Mins,Secs}} = calendar:gregorian_seconds_to_datetime( Elapsed * Total div Current - Elapsed ),
io_lib:format(”~2.10.0B:~2.10.0B:~2.10.0B“, [Hours,Mins,Secs]).

Usage goes something like this:

example(N) ->
PBar = progress_bar:start(”Example“, N),
example_work(N, PBar),
progress_bar:finish(PBar).

example_work(0,_) -> [];
example_work(N, PBar) ->
PBar1 = progress_bar:increment(PBar),
timer:sleep(100),
example_work(N-1, PBar1).

Enjoy! You can download it here.