|
Posted
over 19 years
ago
by
Daniel Berger
Over the last couple of Ruby releases I’ve made some improvements (with Eric Hodel’s help and blessing) to RDoc for C extensions that I thought I would share with you. If you write C extensions with Ruby then keep reading. If you don’t do C and/or
... [More]
don’t care that much about RDoc, this post may not be that interesting for you. :)
First, and most significantly, you no longer need to use the “Document-class” directive for source files that contain multiple classes and/or classes that don’t match the ‘xxx’ portion of ‘Init_xxx’. Prior to 1.8.6, for example, you might have something like this:
/*
* Document-class: Top
* This is the Top namespace.
*/
/*
* Document-class: Bar
* This is the Bar class
*/
/*
* Document-class: Baz
* This is the Baz class.
*/
void Init_foo(){
VALUE mTop, cBar, cBaz;
mTop = rb_define_module("Top");
cBar = rb_define_class_under(mTop, "Bar", rb_cObject);
cBaz = rb_define_class_under(mTop, "Baz", rb_cObject);
}
I thought that having to explicitly document classes and modules outside of the Init_xxx function using special directives like that was ugly, so I dug into the rdoc source (scary!) and figured out to get this working. The short of it is that you can document your classes and modules in a manner that is much more in line with the way rdoc works for other C elements:
void Init_foo(){
VALUE mTop, cBar, cBaz;
/* This is the top namespace */
mTop = rb_define_module("Top");
/* This is the Bar class */
cBar = rb_define_class_under(mTop, "Bar", rb_cObject);
/* This is the Baz class */
cBaz = rb_define_class_under(mTop, "Baz", rb_cObject);
}
This is a much nicer DWIM approach in my opinion. No special directives required.
The second improvement was a minor one. In pure Ruby you can have “personal comments” in methods that won’t be picked up in the rdoc by using “–” to delineate them:
# This is the foo method. There are many like it but this one is mine.
#--
# This was a major pain to implement for MS Windows.
def foo
"hello"
end
In the above example the comment “This was a major pain to implement for MS Windows” is not picked up for the final rdoc output. Prior to Ruby 1.8.5 there was no similar mechanism for C extensions. Now, however, you can use the same approach:
/*
* This is the foo method. There are many like it but this one is mine.
*--
* This was a major pain to implement for MS Windows.
*/
The last thing I’ll mention is an improvement in the way constants are documented. Prior to 1.8.6 the constant definitions were parsed literally because rdoc has no way of knowing what a constant C value is. For example, if you had something like this:
#define FOO_VERSION "1.2.0"
void Init_foo(){
VALUE cFoo = rb_define_class("Foo", rb_cObject);
/* The version of this package */
rb_define_const(cFoo, "VERSION", rb_str_new2(FOO_VERSION));
}
The end result would be “VERSION = rb_str_new2(FOO_VERSION)”. Not what we want. Now, however, you can specify the literal value yourself by using the “value: comment” syntax:
#define FOO_VERSION "1.2.0"
void Init_foo(){
VALUE cFoo = rb_define_class("Foo", rb_cObject);
/* 1.2.0: The version of this package */
rb_define_const(cFoo, "VERSION", rb_str_new2(FOO_VERSION));
}
Enjoy!
[Less]
|
|
Posted
over 19 years
ago
by
Jim Alateras
Here is a nice looking javascript date widget that you can embed in your RoR application. Instructions on installing the widget into your Rails applications is provided on the home page.
I’ll definitely be giving it a whirl.
|
|
Posted
over 19 years
ago
by
Ryan Leavengood
I haven’t posted here in a very long time, but I recently got a full-time job using Ruby and Rails (hurray) so Ruby is more on my mind lately. In fact I’ve gotten a better understanding of what life is like for the average Rails developer by seeing
... [More]
how my co-worker Alex writes his Ruby code. Now Alex is a smart guy, he has been doing web-sites for years, is proficient in ColdFusion, PHP , Flash, HTML and CSS, yet his Ruby code is not always as elegant as he or I would like. Of course I’ve been using Ruby for almost 6 years so know it quite well (and that is a big reason why I was hired.)
Still even I find the occasional new nugget and figured this blog would be a good forum to expose some of my new insights. This way other Rails developers like Alex who aren’t as proficient in Ruby as they would like can benefit from my experience.
Recently I was perusing the documentation for the Enumerable module and took a closer look at the grep method. This method is surprisingly more powerful than it might seem at first glance. To learn more, please continue reading this entry…
What the Documentation Says
First, let’s describe the basic workings of the grep method, straight from the Ruby documentation:
enumObj.grep( pattern ) -> anArray
enumObj.grep( pattern ) {| obj | block } -> anArray
Returns an array of every element in enumObj for which Pattern === element. If the
optional block is supplied, each matching element is passed to it, and the
block's result is stored in the output array.
The most obvious use of grep is with arrays of Strings and a RegExp as the argument:
irb(main):001:0> names = ["Joe", "Bill", "Jill", "Susan", "Sam"]
=> ["Joe", "Bill", "Jill", "Susan", "Sam"]
irb(main):002:0> names.grep(/^J/)
=> ["Joe", "Jill"]
irb(main):003:0> names.grep(/^S/) {|name| name.upcase}
=> ["SUSAN", "SAM"]
Getting Deeper
But the key thing to remember is that grep actually uses the === operator when comparing the argument passed to each element in the Array. So any class that intelligently implements that operator can be used:
irb(main):004:0> numbers = [1, 2, 3, 4, 5, 6, 8, 9]
=> [1, 2, 3, 4, 5, 6, 8, 9]
irb(main):005:0> numbers.grep(3..6)
=> [3, 4, 5, 6]
irb(main):006:0> dates = [Date.new(2000, 1, 1), Date.new(2002, 2, 2),
Date.new(2004, 3, 3), Date.new(2006, 4, 4)]
=> [#<Date: 4903089/2,0,2299161>, #<Date: 4904615/2,0,2299161>,
#<Date: 4906135/2,0,2299161>, #<Date: 4907659/2,0,2299161>]
irb(main):007:0> dates.grep(Date.new(2001, 1, 1)..Date.new(2005, 1, 1)) {|date| date.to_s }
=> ["2002-02-02", "2004-03-03"]
irb(main):008:0> class Base;end
=> nil
irb(main):009:0> class Child1 < Base;end
=> nil
irb(main):010:0> class Child2 < Base;end
=> nil
irb(main):011:0> class NotAChild;end
=> nil
irb(main):012:0> objects = [Child1.new, NotAChild.new, Child2.new]
=> [#<Child1:0x2df6ce8>, #<NotAChild:0x2df6cd4>, #<Child2:0x2df6cc0>]
irb(main):013:0> objects.grep(Base)
=> [#<Child1:0x2df6ce8>, #<Child2:0x2df6cc0>]
In the above examples the Range#=== and Class#=== operators to grep through numbers, dates and instances of classes.
The Magical Transformation Block
Something that I haven’t yet talked about, but which I’ve used in the examples, is the block passed to grep. This acts much like the block in Enumerable#map, taking a member of the array and returning it transformed in some way. Above I’ve made Strings uppercase and turned dates into more readable Strings, but this block can be as complex as you might need.
Making Your Own Classes “Grep-Friendly”
If you have classes which you might want to use with grep, all you need to do is implement an intelligent === method for whatever you will be passing to grep. In fact, as an example I decided to implement a Magic class which takes a block for use in the === method:
class Magic
def initialize(&block)
@block = block
end
def ===(other)
@block.call(other)
end
end
class Animal < Struct.new(:name, :sound, :class)
def to_s
"#{name}'s go '#{sound}'"
end
end
animals = [
Animal.new("Cow", "Moo!", "Mammal"),
Animal.new("Snake", "Hiss!", "Reptile"),
Animal.new("Dog", "Bark!", "Mammal"),
Animal.new("Eagle", "Go America!", "Bird"),
Animal.new("Cat", "Meow!", "Mammal"),
Animal.new("Shark", "Da Dum, Da Dum, Da Dum!", "Fish")
]
puts animals.grep(Magic.new {|a| a.class == "Mammal"})
# Results in:
# Cow's go 'Moo!'
# Dog's go 'Bark!'
# Cat's go 'Meow!'
Conclusion
I hope this relatively brief look into the Ruby Core was informative and will help any readers produce more elegant and maintainable Ruby code in their applications. As I find other interesting methods and uses I’ll post about them. [Less]
|
|
Posted
over 19 years
ago
by
Gregory Brown
This came up in #camping today and I figured it was worth at least a mention:
Vanilla HashWithIndifferentAccess is slightly more choosy than Camping’s.
A quick irb session with each shows the difference.
From active_support
>> require
... [More]
"active_support"
=> true
>> a = HashWithIndifferentAccess.new
=> {}
>> a.apple
NoMethodError: undefined method `apple' for {}:HashWithIndifferentAccess
from (irb):4
>> a.apple "bar"
NoMethodError: undefined method `apple' for {}:HashWithIndifferentAccess
from (irb):5
>> a.apple = "bar"
NoMethodError: undefined method `apple=' for {}:HashWithIndifferentAccess
from (irb):6
From camping
>> require "camping"
=> true
>> a = HashWithIndifferentAccess.new
=> {}
>> a.apple
=> nil
>> a.apple "bar"
NoMethodError: apple
from /usr/local/lib/ruby/gems/1.8/gems/camping-1.5/lib/camping.rb:51:in `method_missing'
from (irb):5
>> a.apple = "bar"
=> "bar"
This is not a complaint, just an observation I hope will be helpful. :) [Less]
|
|
Posted
over 19 years
ago
by
Jim Alateras
Since picking up RoR I have had to dig in to technologies which I had previously only glanced at. One of these is CSS, part of the DHTML set of technologies.
The experience has been rewarding and at times frustrating but the outcomes has been
... [More]
positive. It is a technology that people need to get their heads around in order to develop an effective and usable front end to your web application.
Here are some resources that eased the learning curve
Books
CSS Mastery
Bulletproof Web Design
Debugging Tools
Firebug Add-on for Firefox
Web Developer Add-on for Firefox
Editors
Style Master CSS Editor
[Less]
|
|
Posted
over 19 years
ago
by
Gregory Brown
The following may be a bit of an ‘Advanced NubyGem’ but I think this is an interesting idiom that most people will have to work with.
Sometimes in Ruby you’ll see things, both in core and third party libraries, that look a bit like class names that
... [More]
take arguments.
You may of already seen these in the form of Integer(), Array(), etc.
>> Integer(1)
=> 1
>> Integer("1")
=> 1
>> Integer("")
ArgumentError: invalid value for Integer: ""
from (irb):3:in `Integer'
from (irb):3
These weird looking methods are just alternate constructors. They can really come in handy as a way to simplify the most common ways of building a given object, or giving them some different behaviors.
Here is an example from Ruport:
The long way of constructing a Table object:
table = Ruport::Data::Table.new :data => [[1,2,3],[4,5,6]],
:column_names => %w[a b c]
This is the shortcut interface:
table = Table(%w[a b c]) << [1,2,3] << [4,5,6]
This is usually less typing and looks a little cleaner. Of course, it doesn't support the same exact options of the original constructor, but that's what we're going for afterall.
How it's done
Implementing these methods is as simple as using capitalized method names. In Ruport, we are currently a little surly and do this right on Kernel so you can get the constructors everywhere:
module Kernel
def Table(*args)
#implementation here
end
end
A safer way
Instead of sticking these methods in Kernel, you can play it safe and put them in a module,
this way, they only are available where you include them. For example, if enough people complain, we’ll probably do something like this:
module Ruport::Data::Shortcuts
def Table(*args)
#....
end
end
This way, people would be able to use these shortcuts just in certain classes by including the module in them. If you’re worried about your names conflicting with others, this might be a good idea.
Don’t Overuse Your Shortcuts!
I should fix this problem before I tell folks not to do it, but right now bits of Ruport code use the shortcut methods internally. Unless you have a really compelling reason (other than laziness) to do this, Don’t!
The very thing that makes it ’safe enough’ to stick these shortcuts in core is that a conflict should only break the shortcut. If you use your shortcuts internally in your code, there is a chance of some serious issues if things collide. [Less]
|
|
Posted
over 19 years
ago
by
pat eyler
RubyCentral is once again a Mentoring Organization for the Google Summer of Code. While we have a very strong pool of mentoring candidates, we’d love to see more student/project applications.
Applying as a student is pretty easy, all you need to do
... [More]
is go here and follow the directions. If you’ve already got an idea in the Ruby, RoR, JRuby, Xruby, rubinius, etc. space please submit it. If you’re stuck, take a look at some suggested ideas here.
Do move quickly though. The window for applications closes March 24th. [Less]
|
|
Posted
over 19 years
ago
by
Gregory Brown
This blog has some of the best Ruby talent floating around on it.
Problem is, it seems like many folks are too busy, too tied up with other blogs, or too (something) to post here.
Some of us want to turn that around. I’ve been talking community for
... [More]
the last week or so, and I’d like to start eating my own dog food right here at home.
We’ve already started discussions on the internal mailing list, I’m willing to open Pandora’s box and ask you readers what you are looking for. What things do you like and want to see more of? What things do you dislike and want to see banned from ORA and possible chased by an army of undead pirates?
If you go back and look at the list of authors we have here, there is serious potential for a cool ruby resource. Problem is, no one knows quite what to do anymore, since the overall feel over here is a little fragile.
I was pretty excited when O’Reilly set up a Ruby blog. I’d like to see that excitement restored among the bloggers here. So, readers, what can we do to make you happy?
If it involves Chunky Bacon, so be it! [Less]
|
|
Posted
over 19 years
ago
by
Jim Alateras
Today I came across this article, which describes how to install RoR on a Sun Java System Web Server 7.0.
|
|
Posted
over 19 years
ago
by
Jim Alateras
Rails for All is a RoR web site, which is interested in promoting RoR as the platform of choice for user centric, database-backed web application. The site allows you to promote your Ruby or RoR users group and also register yourself or your company as RoR developers.
RoR content portals are springing up all over the place.
|