Kurt Schrader
From my coworker Ryan, while I was complaining about figuring out yet another DSL in Rails (YADSLIR?):
When you're working with Rails, you don't just get to experience the pleasure of using Ruby, you also get to experience the pleasure of learning 40 fucking different DSLs on top of it
Brian W. McCallister
I have been corrupted by JavaScript. Ruby really annoyed me when I
could not just add properties and functions totally willy-nilly to
instances. Ruby makes it easy to reopen classes, or even instances,
but it is not so obvious how to do so without creating a new scope
(and hence losing your closure).
The ~standared mechanism is to do something vicious like this:
foo = "hello"
msg = "woot!"
class< "woot!"
Aside from the fact that this is a vicious hack, it relies on the
fact that send lets you invoke private methods
(define_method) on the singleton class (more recently
going by the alias of eigenclass) of foo. This is pretty
much a bug and a violation of the object. It's like object rape, or
something.
A nicer way to do it, to my mind, is to use anonymous modules. The
really nice part of using anonymous modules is that the
Module constructor takes a block which is evaluated in
the context of the new module, letting you legally call
private methods, like define_method.
moo = "TOOW!"
foo.extend(Module.new { attr_accessor :baz })
foo.extend(Module.new { define_method(:toow) { puts moo }} )
foo.baz = 7
foo.toow # => "TOOW!"
moo = "MOOO!!"
foo.toow # => "MOOO!!"
This has the same effect and no nasty exploitation of the send bug!
Of course, with javascript, it is just...
foo = "woot"
foo.bar = 7
foo.stuff = function(a, b, c) { a * b * c }
I still like ruby more, though ;-)
Brian W. McCallister
After the Silicon Valley Ruby Conference I wanted
to hack some at a declarative language for web service
orchestration. Tests pass, but the web service bindings
don't exist yet =( Right now it can be used as a nice
declarative process for... er, ruby?
class TestProcess < Test::Unit::TestCase
def test_example
p = Processor::process :wombats do
receive :message
forward :message, :to => :provisioning,
:save_reply => :provision_response
forward :message, :to => :payroll
if_test( proc { provision_response =~ /example/ } ) do
transform :message, :with => :some_transformer,
:save_in => :transformed_message
forward :transformed_message, :to => :server_group
end
forward :provision_response, :to => :helpdesk
end
The rest of the test case just mocks out the services
needed and tests that the things works. Not as exciting
but here it is for completeness =)
p.services[:provisioning] = lambda do |process, msg|
@provision_msg = msg
assert process.expecting_response?
"address@example.com"
end
p.services[:payroll] = lambda do |process, msg|
@payroll_msg = msg
end
p.services[:server_group] = lambda do |process, msg|
@server_group_msg = msg
end
p.services[:helpdesk] = lambda do |process, msg|
process.suspend
end
msg = OpenStruct.new
p.start msg
assert_equal @provision_msg, msg
assert_equal @payroll_msg, msg
assert_equal @server_group_msg, "address@example.com"
assert_equal p.transformed_msg, "address@example.com"
assert p.suspended?
p.resume "back from helpdesk"
assert p.completed?
end
end
For the most part I am kind of happy with it. The nasty
wart of
if_test( proc { provision_response =~ /example/ } ) do
transform :message, :with => :some_transformer,
:save_in => :transformed_message
forward :transformed_message, :to => :server_group
end
annoys me. It's needed to lazily evaluate the construct, using
a real if there evaluates it at the wrong time. Astute
code readers will also notice I am not testing the transform. Haven't
done that yet -- will probably remove it as a first class concept
if I do anything more with the code, a transform is just a local
service, and services are all wrapped in ruby methods, so instead
of importing the service, just provide the transform and voila, your
toast is burnt.
Wish ruby continuations were migratable/serializable.
Brian W. McCallister
So, ruby threads have issues. Multiprocessing, on the other hand,
works great. I have been doing stuff like:
#!/usr/bin/env ruby
require 'drb'
URI = "drbunix:///tmp/foopie"
class Master
def initialize(count=100)
@jobs = []
count.times do |i|
@jobs << "Job ##{i}"
end
end
def take(n)
taken = []
while taken.length < n && !@jobs.empty?
taken << @jobs.shift
end
taken
end
end
DRb.start_service URI, Master.new
pids = []
10.times do |i|
pids << fork do
DRb.start_service
master = DRbObject.new_with_uri URI
until (jobs = master.take(2)).empty?
jobs.each do |j|
puts j
sleep rand
end
end
end
end
puts "started children"
pids.each { |pid| Process.wait(pid) }
To slam though jobs in ruby. Doing it over
unix sockets instead of tcp is just nicer =) It just spreads the
workload across processes instead of threads.
Brian W. McCallister
So, it is right in the docs, but somehow I overlooked it... You can
do
DRb over unix sockets dirt easily =)
require 'drb'
class Logger
def log m
puts m
end
end
DRb.start_service "drbunix:///tmp/logger", Logger.new
Note the URI.
require 'drb'
DRb.start_service
logger = DRbObject.new_with_uri "drbunix:///tmp/logger"
logger.log "Woot!"
=)
Dion Almaer
As I hang out at Rails user groups, chat with friends using Rails, and others at conferences and the like, I have seen a few groups of Rails users out there.
Consultants
Ah the consultants. If you have been to a show like No Fluff Just Stuff you would have noticed that last years season had more questions on Rails than Java (or so it felt, which was a little painful!).Many of the people up on the panel were able to answer the questions (or at least give their opinion) since they had actually used Rails. Many of them were talking about JSF and other Java web frameworks the year before, but had moved on for some of their projects.
Why have these alpha geeks moved on?
Positive view: Consultants often get to start new projects. They do not have the same baggage (baggage in this case == legacy code that runs and makes the business money!) that IT departments often have. If you have a million lines of code in Java, WebWork, Spring, Hibernate, would it make sense to jump over to Rails? You have the knowledge of those frameworks inside and out. You have helper libraries to make your life easier. You have nailed deployment. Does it make sense to change? The consultant moving on to client.next gets to start a new project from scratch and wants to play with the new toy. He has heard about the potential of Rails and wants to test out the hype. This has always happened, and is the reason that many have deployed Struts, WebWork, JSF, and Tapestry applications in a fairly short time period. For many of the current crop, they enjoyed the Rails experience, and they haven't jumped to another framework..... yet!
Negative view: Consultants need new technology to master to sell themselves! The yet from above means that this year they gamble on Rails, but who knows what it will be next year. I personally think that Rails has legs, and the length of time that a consultant spends with a technology shows how changing that technology is. For example, I had used Spring on every Java project for the last 1.5+ years. Spring was useful enough to me that it made sense to use it on all of those projects. Therefore, major points for Spring. This can be said for JUnit (until TestNG comes in ;) and many other tools (even IntelliJ IDEA!).
Startups
Startups such as ODEO, of course 37 Signals, and the like have been strong users
of Rails. They get the benefit of.... being startups!
The green field is what they see, and their goal is to come up with technology a
s fast as possible to start to make some $ somehow (or the business model may be
to do a beta and get bought out by G/Y/MSFT).
They do not have the luxury of legacy code (again: code that runs and makes $) but they do have the luxury of making a choice from scratch.
Rails thrives on green field projects.
Students
About half of my local Rails group consists of students at the local college. The first presentation was from a student. Rails fits them nicely as it is a quick environment to whip out their projects.
I remember using this same advantage back when I was at university. The class was using C++ to build a web app, and I hacked together something using Perl, and had far more time to enjoy the fun parts of college life.
The head Java instructor is very much in the Rails camp. He talks about how hard it is to teach Java in comparison. There is so much to teach in public static void main(String args[]) and he has tried top down, bottom down, andevery other way (using BlueJ and ...).
Of course...
This isn't a definitive list and of course it doesn't mean that any other type isn't using Rails, but it was a little interesting.
Dion Almaer
If you have used Rails for non-trivial applications, you have probably run into a lot of "Hmm, what would be the best way to do this?" moments.
As soon as you tread off of the simple path, you need to think :)
Rails Recipes has been a saviour for a few of the items that I care about. The Wiki doesn't cut it. A co-worker spent a few hours working on ideas from the Wiki. Then he cracked open Rails Recipes, found an exact solution, and it actually worked right away :)
The book is in beta form now, and will shortly be finished. I am sure there will be several versions in the future as Chad finds more and more useful ideas.
Lance Ball
Chris Petrilli writes what I think is an insightful post on getting things done in a software project. An underlying issue – though not really stated outright – is the whole Java/J2EE vs. Ruby/Rails debate that will never really have an end.
But I think his most salient points transcend language wars and hit on some key issues.
If you deliver an “enterprise solution” in 2 years, and I deliver what you degrade as a “non-enterprise solution” next week, whose solution do you think earns more money for the organization? Who do you think abates the costs faster? Most importantly, who do you think learns where the mistakes are and the real requirements exist.
It’s all about making software that works and is delivered on time. If I get that done, maybe I can have some money in the budget to scale it if I need to. But so much is really unknown, and to act as though you can actually forsee the future is sometimes a fools folly.
Not all problems are knowable. Until you accept this perspective, you will continually pursue the perfect to the deficit of the good.
Until then, I plan on testing first, taking small steps, and delivering something that works every couple of weeks.
Brian W. McCallister
So, Martin released a first
showing at his wicked cool Atom binding library
for ruby:
require 'atom'
require 'net/http'
require 'uri'
str = Net::HTTP::get(URI::parse('http://blog.ning.com/atom.xml'))
feed = Atom::Feed.new(str)
feed.entries.each { |entry|
puts "'#{entry.title}' by #{entry.authors.first.name}"
}
I like this example more, though ;-)
Meanwhile, Obie
apparently leaked ActiveMessagingM-Del
a13g. Woot!
It's good to see Stomp
getting wider usage.
class HelloWorldProcessor < ActiveMessaging::Processor
subscribes_to :hello_world
publishes_to :hello_world
def on_message(message)
puts "received: " + message.body
publish :message => "Hello world!"
end
end
Cool stuff all around!
Martin
I've been looking for a Ruby library for parsing
Atom 1.0. The only one I could find was
FeedTools. Unfortunately, it's intended to be a universal feed-parsing library and not quite what I need.
As a result, I decided to build my own. The
project is hosted at RubyForge and the source code is available under the MIT license.
It is still in its early stages, so don't expect much at this point. So far, it understands most atom:* elements and attributes but doesn't perform validation.
The interface is fairly simple. For example, you can do this:
require 'atom'
require 'net/http'
require 'uri'
str = Net::HTTP::get(URI::parse('http://blog.ning.com/atom.xml'))
feed = Atom::Feed.new(str)
feed.entries.each { |entry|
puts "'#{entry.title}' by #{entry.authors.first.name} on #{entry.published.strftime('%m/%d/%Y')}"
}
Give it a try, play with it. Comments are welcome!