Your SlideShare is downloading. ×
Dsl
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

×
Saving this for later? Get the SlideShare app to save on your phone or tablet. Read anywhere, anytime – even offline.
Text the download link to your phone
Standard text messaging rates apply

Dsl

1,010

Published on

Writing a DSL in Ruby

Writing a DSL in Ruby

Published in: Technology
0 Comments
1 Like
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
1,010
On Slideshare
0
From Embeds
0
Number of Embeds
0
Actions
Shares
0
Downloads
30
Comments
0
Likes
1
Embeds 0
No embeds

Report content
Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
No notes for slide
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • Transcript

    • 1. Writing a DSL in Ruby Why Ruby makes it soooo easy!
    • 2. DSL!!!!11one
    • 3. domain specific language TL;DR➡ Customized to specific problem domain➡ Evaluated in context of the domain➡ Helps creating ubiquitous language
    • 4. internal vs. external„Internal DSLs are particular ways of using a host language to give the host language the feel of a particular language.“„External DSLs have their own custom syntaxand you write a full parser to process them.“
    • 5. internal vs. external„Internal DSLs are particular ways of using a host language to give the host language the feel of a particular language.“„External DSLs have their own custom syntaxand you write a full parser to process them.“
    • 6. internal vs. external„Internal DSLs are particular ways of using a host language to give the host language the feel of a particular language.“ er wl Fo tin ar„External DSLs have their own custom syntax Mand you write a full parser to process them.“
    • 7. Rails, collection of DSLs • Routes • Tag- / Form-Helpers • Builder • Associations, Migrations, ... • Rake / Thor • Bundler • [...]
    • 8. all about API designRuby makes it easy to create DSL: • expressive & concise syntax • open classes • mixins • operator overloading • [...]
    • 9. Gregory Brown Russ Olsen
    • 10. DSL by EXAMPLE
    • 11. Method Paramslink_to "Articles", { :controller => "articles" }, :id => "news", :class => "article"
    • 12. Method Paramslink_to "Articles", { :controller => "articles" }, :id => "news", :class => "article"def doit_with(some, parameters) # does itend
    • 13. Method Paramslink_to "Articles", { :controller => "articles" }, :id => "news", :class => "article"def doit_with(some, parameters) def doit_with(mandatory, optional=nil, parameters=nil) # does it # does itend end
    • 14. Method Paramslink_to "Articles", { :controller => "articles" }, :id => "news", :class => "article"def doit_with(some, parameters) def doit_with(mandatory, optional=nil, parameters=nil) # does it # does itend enddef doit_with(options={:named => parameter}) # does itend
    • 15. Method Paramslink_to "Articles", { :controller => "articles" }, :id => "news", :class => "article"def doit_with(some, parameters) def doit_with(mandatory, optional=nil, parameters=nil) # does it # does itend enddef doit_with(options={:named => parameter}) def doit_with(mandatory, *optional_paramters) # does it # does itend end
    • 16. Method Paramslink_to "Articles", { :controller => "articles" }, :id => "news", :class => "article"def doit_with(some, parameters) def doit_with(mandatory, optional=nil, parameters=nil) # does it # does itend enddef doit_with(options={:named => parameter}) def doit_with(mandatory, *optional_paramters) # does it # does itend end def doit_with(*args) options = args.pop if Hash === args.last name = args.first # [...] raise ArgumentError, Bad combination of parameters unless args.size == 1 # does it end
    • 17. BlocksTwitter.configure do |config| config.consumer_key = YOUR_CONSUMER_KEY config.consumer_secret = YOUR_CONSUMER_SECRETend
    • 18. Blocks Twitter.configure do |config| config.consumer_key = YOUR_CONSUMER_KEY config.consumer_secret = YOUR_CONSUMER_SECRET enddef doit_with(&explicit_block) explicit_block.callend
    • 19. Blocks Twitter.configure do |config| config.consumer_key = YOUR_CONSUMER_KEY config.consumer_secret = YOUR_CONSUMER_SECRET enddef doit_with(&explicit_block) def doit_with_implicit_block explicit_block.call yield if block_given?end end
    • 20. Blocks Twitter.configure do |config| config.consumer_key = YOUR_CONSUMER_KEY config.consumer_secret = YOUR_CONSUMER_SECRET enddef doit_with(&explicit_block) def doit_with_implicit_block explicit_block.call yield if block_given?end end def doit_with_block_for_configuration yield self end
    • 21. Blocks Twitter.configure do |config| config.consumer_key = YOUR_CONSUMER_KEY config.consumer_secret = YOUR_CONSUMER_SECRET enddef doit_with(&explicit_block) def doit_with_implicit_block explicit_block.call yield if block_given?end end def doit_with_block_for_configuration yield self enddef doit_with(&arity_sensitive_block) arity_sensitive_block.call foo, bar if arity_sensitive_block.arity == 2end
    • 22. Instance EvalTwitter.configure do |config| config.consumer_key = YOUR_CONSUMER_KEY config.consumer_secret = YOUR_CONSUMER_SECRETend
    • 23. Instance EvalTwitter.configure do |config| consumer_key = YOUR_CONSUMER_KEY config.consumer_key = YOUR_CONSUMER_KEY consumer_secret = YOUR_CONSUMER_SECRET config.consumer_secret = YOUR_CONSUMER_SECRETend
    • 24. Instance EvalTwitter.configure do |config| consumer_key = YOUR_CONSUMER_KEY config.consumer_key = YOUR_CONSUMER_KEY consumer_secret = YOUR_CONSUMER_SECRET config.consumer_secret = YOUR_CONSUMER_SECRETend def doit_with(&instance_eval_block) if instance_eval_block.arity == 0 # could also be class_eval, module_eval self.instance_eval(&instance_eval_block) else instance_eval_block.call self end end
    • 25. Method MissingClient.find_by_firstname_and_lastname_and_gender(uschi, mueller, :female)
    • 26. Method MissingClient.find_by_firstname_and_lastname_and_gender(uschi, mueller, :female) METHOD_PATTERN = /^find_by_/ def method_missing(method, *args, &block) if method.to_s =~ METHOD_PATTERN # finder magic else super end end
    • 27. Method MissingClient.find_by_firstname_and_lastname_and_gender(uschi, mueller, :female) METHOD_PATTERN = /^find_by_/ METHOD_PATTERN = /^find_by_/ def method_missing(method, *args, &block) if method.to_s =~ METHOD_PATTERN def method_missing(method, *args, &block) # finder magic if method.to_s =~ METHOD_PATTERN else # finder magic super else end end super end end respond_to?(method) def return true if method =~ METHOD_PATTERN super end
    • 28. Code Generation client.firstname = uschi puts client.lastname
    • 29. Code Generation client.firstname = uschi puts client.lastname def generate(name) self.class.send(:define_method, name){puts name} eval("def #{name}() puts #{name} end") def some_method(name) puts name end # [...] end
    • 30. Makrosclass Client < ActiveRecord::Base has_one :address has_many :orders belongs_to :roleend
    • 31. Makrosclass Client < ActiveRecord::Base has_one :address has_many :orders belongs_to :roleend class << self def has_something # macro definition end end
    • 32. Hooks$ ruby simple_test.rb
    • 33. Hooks$ ruby simple_test.rb at_exit do # shut down code end
    • 34. Hooks $ ruby simple_test.rb at_exit do # shut down code endinherited, included, method_missing, method_added,method_removed, trace_var, set_trace_func, at_exit ...
    • 35. Hooks $ ruby simple_test.rb at_exit do # shut down code endset_trace_func proc { |event, file, line, id, binding, classname| inherited, included, method_missing, method_added, printf "%8s %s:%-2d trace_var, set_trace_func, line, id,... method_removed, %10s %8sn", event, file, at_exit classname}
    • 36. Core Extensions text.blank?
    • 37. Core Extensions text.blank? class Object def blank? nil? || (respond_to?(:empty?) && empty?) end end
    • 38. Core Extensions text.blank? class Object def blank? nil? || (respond_to?(:empty?) && empty?) end unless method_defined?(:blank?) end
    • 39. Core Extensions text.blank?module MyGem class Object module CoreExtensions module blank? def Object defnil? || (respond_to?(:empty?) && empty?) blank? end unless method_defined?(:blank?) respond_to?(:empty?) ? empty? : !self end end end endendObject.send :include, MyGem::CoreExtensions::Object
    • 40. Ruby techniques✓Method Params ✓Makros✓Blocks ✓Code generation✓Instance Eval ✓Hooks✓Method Missing ✓Core Extensions
    • 41. External DSLRuby Tools: • Switch Cases • Regular ExpressionsRuby Parser: • Treetop • RACC
    • 42. Links★ Eloquent Ruby★ Ruby Best Practices★ Domain Specific Languages★ Rebuil★ Treetop
    • 43. Over and Out
    • 44. Over and Out

    ×