Diese Präsentation wurde erfolgreich gemeldet.
Wir verwenden Ihre LinkedIn Profilangaben und Informationen zu Ihren Aktivitäten, um Anzeigen zu personalisieren und Ihnen relevantere Inhalte anzuzeigen. Sie können Ihre Anzeigeneinstellungen jederzeit ändern.

Dsl

1.467 Aufrufe

Veröffentlicht am

Writing a DSL in Ruby

Veröffentlicht in: Technologie
  • Als Erste(r) kommentieren

Dsl

  1. 1. Writing a DSL in Ruby Why Ruby makes it soooo easy!
  2. 2. DSL!!!!11one
  3. 3. domain specific language TL;DR➡ Customized to specific problem domain➡ Evaluated in context of the domain➡ Helps creating ubiquitous language
  4. 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. 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. 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. 7. Rails, collection of DSLs • Routes • Tag- / Form-Helpers • Builder • Associations, Migrations, ... • Rake / Thor • Bundler • [...]
  8. 8. all about API designRuby makes it easy to create DSL: • expressive & concise syntax • open classes • mixins • operator overloading • [...]
  9. 9. Gregory Brown Russ Olsen
  10. 10. DSL by EXAMPLE
  11. 11. Method Paramslink_to "Articles", { :controller => "articles" }, :id => "news", :class => "article"
  12. 12. Method Paramslink_to "Articles", { :controller => "articles" }, :id => "news", :class => "article"def doit_with(some, parameters) # does itend
  13. 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. 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. 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. 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. 17. BlocksTwitter.configure do |config| config.consumer_key = YOUR_CONSUMER_KEY config.consumer_secret = YOUR_CONSUMER_SECRETend
  18. 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. 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. 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. 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. 22. Instance EvalTwitter.configure do |config| config.consumer_key = YOUR_CONSUMER_KEY config.consumer_secret = YOUR_CONSUMER_SECRETend
  23. 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. 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. 25. Method MissingClient.find_by_firstname_and_lastname_and_gender(uschi, mueller, :female)
  26. 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. 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. 28. Code Generation client.firstname = uschi puts client.lastname
  29. 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. 30. Makrosclass Client < ActiveRecord::Base has_one :address has_many :orders belongs_to :roleend
  31. 31. Makrosclass Client < ActiveRecord::Base has_one :address has_many :orders belongs_to :roleend class << self def has_something # macro definition end end
  32. 32. Hooks$ ruby simple_test.rb
  33. 33. Hooks$ ruby simple_test.rb at_exit do # shut down code end
  34. 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. 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. 36. Core Extensions text.blank?
  37. 37. Core Extensions text.blank? class Object def blank? nil? || (respond_to?(:empty?) && empty?) end end
  38. 38. Core Extensions text.blank? class Object def blank? nil? || (respond_to?(:empty?) && empty?) end unless method_defined?(:blank?) end
  39. 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. 40. Ruby techniques✓Method Params ✓Makros✓Blocks ✓Code generation✓Instance Eval ✓Hooks✓Method Missing ✓Core Extensions
  41. 41. External DSLRuby Tools: • Switch Cases • Regular ExpressionsRuby Parser: • Treetop • RACC
  42. 42. Links★ Eloquent Ruby★ Ruby Best Practices★ Domain Specific Languages★ Rebuil★ Treetop
  43. 43. Over and Out
  44. 44. Over and Out

×