Created
November 7, 2014 15:20
-
-
Save adamcooke/4ea4bf64f804c2e714c0 to your computer and use it in GitHub Desktop.
The complete code from my DSL tutorial at http://blog.atechmedia.com/ruby-dsls-for-fun/
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class AddressBook | |
def contacts | |
@contacts ||= [] | |
end | |
def self.load_from_path(path) | |
# Create a new AddressBook instance | |
address_book = self.new | |
# Create a new AddressBookDSL instance | |
address_book_dsl = AddressBookDSL.new(address_book) | |
# Loop through every file in the given path | |
Dir[File.join(path, '*')].each do |file| | |
# Read each file and eval the contents in the address | |
# book's DSL instance. | |
address_book_dsl.instance_eval(File.read(file), file) | |
end | |
# Return the finished address book | |
address_book | |
end | |
end | |
class Contact | |
# Define the basic information attributes | |
attr_accessor :first_name | |
attr_accessor :last_name | |
attr_accessor :company | |
# Define a method to return an array of contact methods for | |
# this contact. | |
def contact_methods | |
@contact_methods ||= [] | |
end | |
# Define a method to return an array of activities for the | |
# this contact. | |
def activities | |
@activities ||= [] | |
end | |
end | |
class ContactMethod | |
# When we create a new contact method, we'll store the contact | |
# which it is associated with too. | |
def initialize(contact) | |
@contact = contact | |
end | |
# Accessor for returning a contact associated with a ContactMethod | |
attr_reader :contact | |
# Accessors for getting & setting the various properties which | |
# are associated with a ContactMethod. | |
attr_accessor :type | |
attr_accessor :role | |
attr_accessor :value | |
end | |
class AddressBookDSL | |
def initialize(address_book) | |
@address_book = address_book | |
end | |
def contact(&block) | |
# Create a new Contact object instance for our new contact | |
contact = Contact.new | |
# Create a new instance of our Contact DSL (defined in a moment) | |
# and pass it our newly instantiated contact. | |
contact_dsl = ContactDSL.new(contact) | |
# Eval the contacts of the `contact` block within the ContactDSL | |
# instance we just created. | |
contact_dsl.instance_eval(&block) | |
# Add the contact to the array of contacts in our address book | |
@address_book.contacts << contact | |
end | |
end | |
class ContactDSL | |
def initialize(contact) | |
@contact = contact | |
end | |
# When the name method is called, we'll accept the first and | |
# last names and set them as appropriate on our contact class. | |
def name(first_name, last_name) | |
@contact.first_name = first_name | |
@contact.last_name = last_name | |
end | |
# When the company is set, we'll just do the same and set that | |
# on the contact. | |
def company(name) | |
@contact.company = name | |
end | |
# Activities are just passed straight through from the contact | |
# itself so we just return the contact's activities array. | |
def activities | |
@contact.activities | |
end | |
# When a contact method is defined, we'll need to create a new | |
# instance of our ContactMethod class, set the values and then | |
# add it to our contact's contact_method array. | |
def contact_method(type, role, value) | |
method = ContactMethod.new(@contact) | |
method.type = type | |
method.role = role | |
method.value = value | |
@contact.contact_methods << method | |
end | |
def method_missing(name, *values) | |
if values.empty? | |
# If no values are provided, we'll just let Ruby raise an error | |
# as normal. | |
super | |
else | |
# Otherwise, we'll simply call our contact_method method to | |
# add our method. | |
contact_method(name, *values) | |
end | |
end | |
end | |
address_book = AddressBook.new | |
address_book_dsl = AddressBookDSL.new(address_book) | |
address_book_dsl.instance_eval do | |
contact do | |
name 'Joe', 'Bloggs' | |
company 'Bloggs Inc' | |
phone :home, '01234 123123' | |
phone :work, '01555 123555' | |
email :home, "[email protected]" | |
activities << 'Piano Playing' | |
activities << 'Swag Catching' | |
end | |
contact do | |
name 'Potato', 'Man' | |
company 'McCain' | |
phone :mobile, '07123 123123' | |
end | |
end | |
address_book.contacts.each do |contact| | |
puts "------------------------------------------------------------------------" | |
puts "#{contact.first_name} #{contact.last_name}" | |
puts contact.company | |
contact.contact_methods.each do |method| | |
puts " * #{method.type}:#{method.role} #{method.value}" | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment