Scoped Struct
Ever write a ruby class and wish you could organize your methods into sub-objects? Take, for example, a class that represents an NFL player:
class Player
def fumbles_dropped; end
def fumbles_lost; end
def fumbles_recovered; end
def passes_attempted; end
def passes_completed; end
def passes_incomplete; end
def pass_completion_percentage; end
end
But we’re ~Ruby Programmers~ and we write DRY code, right? Wouldn’t it be nicer if you could take all that repetition and eliminate it?
class Player
scope :fumbles do
def dropped; end
def lost; end
def recovered; end
end
scope :passes do
def attempted; end
def completed; end
def incomplete; end
def completion_percentage; end
end
end
And then instead of those long ugly method names, you could just be all like,
my_player.passes.attempted
my_player.passes.completed
my_player.fumbles.recovered
Eez better, yes?
The methods you define in the scoping block, when called, run in the same context as if you defined them on the class itself. So you ccan have them referencing instance variables or other methods of the class as if they were local. Likewise, you can also reference other scoped methods from scoped methods, even from other scopes; just make sure to reference them by their full scoped path:
class Player
def name
"John Rambo"
end
scope :formatting do
def loud_name
name.upcase + '!!!'
end
end
scope :actions do
def scream_my_name
puts "MY NAME IS #{formatting.loud_name}"
end
def scream_twice
2.times{ actions.scream_my_name }
end
end
end
Player.new.actions.scream_twice # prints "MY NAME IS JOHN RAMBO!!!" twice
And that’s not all! The object returned by the scoping method, you can pass it around and it will still act the way you’d expect:
fumble_records = my_players.collect{|player| player.fumbles}
fumble_records.first.dropped
And if you want even more organizational fun, you can stick your methods in modules and then include them in their own scoping blocks:
module Passes
def attempted; end
end
module Fumbles
def dropped; end
end
class Player
scope :passes do
include Passes
end
scope :fumbles do
include Fumbles
end
end
Troubleshooting
One thing that will cause weirdness is if you name a scoped method the same thing as one of your base instance methods. Rename it to something else and all will be well.
Credits
By Mike Ferrier (www.mikeferrier.ca)
Contributions by Hampton Catlin (www.hamptoncatlin.com)