# 1classReportattr_reader:title,:textattr_accessor:formatterdefinitialize(formatter)@title='Monthly Report'@text=['Things are going','really, really well.']@formatter=formatterenddefoutput_report@formatter.output_report(self)endendclassHTMLFormatterdefoutput_report(context)puts('<html>')puts(' <head>')# Output The rest of the report ...puts(" <title>#{context.title}</title>")puts(' </head>')puts(' <body>')context.text.eachdo|line|puts(" <p>#{line}</p>")endputs(' </body>')puts('</html>')endendclassPlainTextFormatterdefoutput_report(context)puts("***** #{context.title} *****")context.text.eachdo|line|puts(line)endendend# 2classReportattr_reader:title,:textattr_accessor:formatterdefinitialize(&formatter)@title='Monthly Report'@text=['Things are going','really, really well.']@formatter=formatterenddefoutput_report@formatter.call(self)endendHTML_FORMATTER=lambdado|context|puts('<html>')puts(' <head>')puts(" <title>#{context.title}</title>")puts(' </head>')puts(' <body>')context.text.eachdo|line|puts(" <p>#{line}</p>")endputs(' </body>')puts('</html>')endPLAIN_FORMATTER=lambdado|context|puts("***** #{context.title} *****")context.text.eachdo|line|puts(line)endend
Observer
classPayrolldefupdate(changed_employee)puts"Cut a new check for #{changed_employee.name}!"puts"His salary is now #{changed_employee.salary}!"endendmoduleSubjectdefinitialize@observers=[]enddefadd_observer(observer)@observers<<observerenddefdelete_observer(observer)@observers.delete(observer)enddefnotify_observers@observers.eachdo|observer|observer.update(self)endendendclassEmployeeincludeSubjectattr_reader:name,:addressattr_reader:salarydefinitialize(name,title,salary)super()@name=name@title=title@salary=salaryenddefsalary=(new_salary)@salary=new_salarynotify_observersendend# libraryclassTicker### Periodically fetch a stock price.includeObservabledefinitialize(symbol)@symbol=symbolenddefrunlastPrice=nilloopdoprice=Price.fetch(@symbol)print"Current price: #{price}\n"ifprice!=lastPricechanged# notify observerslastPrice=pricenotify_observers(Time.now,price)endsleep1endendendclassPrice### A mock class to fetch a stock price (60 - 140).defPrice.fetch(symbol)60+rand(80)endendclassWarner### An abstract observer of Ticker objects.definitialize(ticker,limit)@limit=limitticker.add_observer(self)endendclassWarnLow<Warnerdefupdate(time,price)# callback for observerifprice<@limitprint"--- #{time.to_s}: Price below #@limit: #{price}\n"endendendclassWarnHigh<Warnerdefupdate(time,price)# callback for observerifprice>@limitprint"+++ #{time.to_s}: Price above #@limit: #{price}\n"endendendticker=Ticker.new("MSFT")WarnLow.new(ticker,80)WarnHigh.new(ticker,120)ticker.run
Composite
classTaskattr_accessor:namedefinitialize(name)@name=name;enddefget_time_required0.0endendclassAddDryIngredientsTask<Taskdefinitializesuper('Add dry ingredients')enddefget_time_required1.0endendclassMixTask<Taskdefinitializesuper('Mix that batter up!')enddefget_time_required3.0endendclassAddLiquidsTask<Taskdefinitializesuper('Add Liquids task')enddefget_time_required5.0endendclassCompositeTask<Taskdefinitialize(name)super(name)@sub_tasks=[]enddefadd_sub_task(task)@sub_tasks<<tasktask.parent_task=selfenddefremove_sub_task(task)@sub_tasks.delete(task)enddefget_time_requiredtime=0.0@sub_tasks.each{|task|time+=task.get_time_required}timeendendclassMakeBatterTask<CompositeTaskdefinitializesuper('Make batter')add_sub_task(AddDryIngredientsTask.new)add_sub_task(MixTask.new)add_sub_task(AddLiquidsTask.new)endendtask=MakeBatterTask.newputstask.nameputstask.get_time_required