Where you and Bill, at long last, write some code.
“Enough talking about blocks,” Bill says. “It’s time to focus on today’s job. Let’s call it the RedFlag project.”
RedFlag is a monitor utility for the people in the sales department. It should send the sales folks a message when an order is late, when total sales are too low…basically, whenever one of many different things happens. Sales wants to monitor dozens of different events, and the list is bound to change every week or so.
Luckily for you and Bill, sales has full-time programmers, so you don’t have to write the events yourselves. You can just write a simple Domain-Specific Language. (You can read about DSLs in Appendix 2, .) The sales guys can then use this DSL to define events, like this:
| event "we're earning wads of money" do |
| recent_orders = ... # (read from database) |
| recent_orders > 1000 |
| end |
To define an event, you give it a description and a block of code. If the block returns true, then you get an alert via mail. If it returns false, then nothing happens. The system should check all the events every few minutes.
It’s time to write RedFlag 0.1.
You and Bill put together a working RedFlag DSL in no time:
| def event(description) |
| puts "ALERT: #{description}" if yield |
| end |
| load 'events.rb' |
The entire DSL is just one method and a line that executes a file named events.rb. The code in events.rb is supposed to call back into RedFlag’s event method. To test the DSL, you create a quick events file:
| event "an event that always happens" do |
| true |
| end |
| event "an event that never happens" do |
| false |
| end |
You save both redflag.rb and events.rb in the same folder and run redflag.rb:
<= | ALERT: an event that always happens |
“Success!” Bill exclaims. “If we schedule this program to run every few minutes, we have a functional first version of RedFlag. Let’s show it to the boss.”
Your boss is amused by the simplicity of the RedFlag DSL, but she’s not completely convinced. “The people who write the events will want to share data among events,” she observes. “Can I do this with your DSL? For example, can two separate events access the same variable?” she asks the two of you.
“Of course they can,” Bill replies. “We have a Flat Scope ().” To prove that, he whips up a new events file:
| def monthly_sales |
| 110 # TODO: read the real number from the database |
| end |
| |
| target_sales = 100 |
| |
| event "monthly sales are suspiciously high" do |
| monthly_sales > target_sales |
| end |
| |
| event "monthly sales are abysmally low" do |
| monthly_sales < target_sales |
| end |
The two events in this file share a method and a local variable. You run redflag.rb, and it prints what you expected:
<= | ALERT: monthly sales are suspiciously high |
“Okay, this works,” the boss concedes. “But I don’t like the idea of variables and methods like monthly_sales and target_sales cluttering the top-level scope. Let me show you what I’d like the DSL to look like instead,” she says. Without further ado, the boss grabs the keyboard and starts churning out code like nobody’s business.