SlideShare une entreprise Scribd logo
1  sur  84
Télécharger pour lire hors ligne
Enable Labs @mark_menard
A Tour of Wyriki
Mark Menard
Ruby Nation!
June 7, 2014
@mark_menard !
Enable Labs
Enable Labs @mark_menard
Jim Weirich
Enable Labs @mark_menardhttp://www.flickr.com/photos/langalex
Enable Labs @mark_menard
TDD
Enable Labs @mark_menard
Yea…
whatever…
Enable Labs @mark_menard
What is Wyriki?
Enable Labs @mark_menard
The Wyriki Domain
Page
Wiki
*
1
Create Wiki
Create Page
Update
Page
Create User
Loged
In User
Anony
mous
User
Enable Labs @mark_menard
Business Logic
ActiveRecord
ActionPack
Controllers
MySQL MongoDB PostgreSQL
Redis
Sidekiq
Resque
What was Jim trying to accomplish?
Enable Labs @mark_menard
Testing
Enable Labs @mark_menard
Why?!
!
When?
Enable Labs @mark_menard
Typical Rails
Enable Labs @mark_menard
Create Page
Loged
In User
Action
Controller ::
Base
ActiveRecord
:: Base
Pages
Controller
Application
Controller
Page
Wiki
Enable Labs @mark_menard
Create Page
Loged
In User
Action
Controller ::
Base
ActiveRecord
:: Base
Pages
Controller
Application
Controller
Page
Wiki
Enable Labs @mark_menard
Create Page
Loged
In User
Action
Controller ::
Base
ActiveRecord
:: Base
Pages
Controller
Application
Controller
Page
Wiki
Enable Labs @mark_menard
# app/controllers/pages_controller.rb
def create
@wiki = Wiki.find(params[:wiki_id])
@page = @wiki.pages.new(page_params)
if @page.save
redirect_to [@wiki, @page], notice: "#{@page.name} created"
else
render :new
end
end
Enable Labs @mark_menard
Wyriki Style
Enable Labs @mark_menard
Runners
class Runner
attr_reader :context
!
def initialize(context)
@callbacks = NamedCallbacks.new
@context = context
yield(@callbacks) if block_given?
end
!
def repo
context.repo
end
!
def success(*args)
callback(:success, *args)
end
!
def failure(*args)
callback(:failure, *args)
end
!
def callback(name, *args)
@callbacks.call(name, *args)
args
end
end
class Model < SimpleDelegator
include BlockActiveRecord
! def data
datum = self
while datum.biz?
datum = datum.__getobj__
end
datum
end
! def ==(other)
if other.respond_to?(:data)
data == other.data
else
data == other
end
end
! def biz?
true
end
! def class
data.class
end
! def self.wrap(model)
model ? new(model) : nil
end
! def self.wraps(models)
models.map { |model| wrap(model) }
end
!end
Business
Models
Repositories
module UserMethods
def all_users
Biz::User.wraps(User.all_users)
end
! def new_user(attrs={})
Biz::User.wrap(User.new(attrs))
end
! def find_user(user_id)
Biz::User.wrap(User.find(user_id))
end
! def save_user(user)
user.data.save
end
! def update_user(user, attrs)
user.data.update_attributes(attrs)
end
! def destroy_user(user_id)
User.destroy(user_id)
end
end
Enable Labs @mark_menard
Action
Controller ::
Base
ActiveRecord
:: Base
Page
Controller
Application
Controller
Page
Wiki
Create Page
Runner
<<protocol>>
Repo
Repo
<<protocol>>
context
<<protocol>>
Biz Page
<<protocol>>
Biz Wiki
Biz::Wiki
Biz::Page
<<protocol>>
Wiki Data
<<protocol>>
Page Data
<<wraps>>
<<wraps>>
Enable Labs @mark_menard
Action
Controller ::
Base
ActiveRecord
:: Base
Page
Controller
Application
Controller
Some Model
Runner
Repo
Biz Model
<< wraps >>
<< gets and saves
stuff >>
Enable Labs @mark_menard
Action
Controller ::
Base
ActiveRecord
:: Base
Page
Controller
Application
Controller
Some Model
Runner
Repo
Biz Model
<< wraps >>
<< gets and saves
stuff >>
Enable Labs @mark_menard
Enable Labs @mark_menard
Runners
Enable Labs @mark_menard
Enable Labs @mark_menard
Action
Controller ::
Base
ActiveRecord
:: Base
Page
Controller
Application
Controller
Page
Wiki
Create Page
Runner
<<protocol>>
context
Rails
Not Rails
Create Page
Loged
In User
Enable Labs @mark_menard
This is the !
Domain
Enable Labs @mark_menard
This is the !
Domain
This is Rails
Enable Labs @mark_menard
This is our Context.
Enable Labs @mark_menard
# app/controllers/page_controller.rb
def create
run(Create, params[:wiki_id], page_params) do |on|
on.success { |page|
redirect_to [page.wiki, page], notice: "#{page.name} created"
}
on.failure { |wiki, page|
render :new
}
end
end
Enable Labs @mark_menard
# app/controllers/page_controller.rb
def create
run(Create, params[:wiki_id], page_params) do |on|
on.success { |page|
redirect_to [page.wiki, page], notice: "#{page.name} created"
}
on.failure { |wiki, page|
render :new
}
end
end
Enable Labs @mark_menard
# app/controllers/page_controller.rb
def create
run(Create, params[:wiki_id], page_params) do |on|
on.success { |page|
redirect_to [page.wiki, page], notice: "#{page.name} created"
}
on.failure { |wiki, page|
render :new
}
end
end
Enable Labs @mark_menard
# app/runners/page_runners.rb
class Create < Runner
def run(wiki_id, page_params)
wiki = Wiki.find(params[:wiki_id])
page = wiki.pages.new(page_params)
if page.save
success(page)
else
failure(wiki, page)
end
end
end
Enable Labs @mark_menard
# app/runners/page_runners.rb
class Create < Runner
def run(wiki_id, page_params)
wiki = Wiki.find(params[:wiki_id])
page = wiki.pages.new(page_params)
if page.save
success(page)
else
failure(wiki, page)
end
end
end
# app/controllers/page_controller.rb
def create
Create.new(self, params[:wiki_id], page_params).run do |on|
on.success { |page|
redirect_to [page.wiki, page], notice: "#{page.name} created"
}
on.failure { |wiki, page|
render :new
}
end
end
Enable Labs @mark_menard
# app/runners/page_runners.rb
class Create < Runner
def run(wiki_id, page_params)
wiki = Wiki.find(params[:wiki_id])
page = wiki.pages.new(page_params)
if page.save
success(page)
else
failure(wiki, page)
end
end
end
# app/controllers/page_controller.rb
def create
Create.new(self, params[:wiki_id], page_params).run do |on|
on.success { |page|
redirect_to [page.wiki, page], notice: "#{page.name} created"
}
on.failure { |wiki, page|
render :new
}
end
end
Enable Labs @mark_menard
Action
Controller ::
Base
ActiveRecord
:: Base
Page
Controller
Application
Controller
Page
Wiki
Create Page
Runner
<<protocol>>
context
Rails
Not Rails
Create Page
Loged
In User
Enable Labs @mark_menard
Enough Architecture! !
What about the Ruby!!
!
How did Jim actually !
do the callbacks and the
runners?
Enable Labs @mark_menard
Runner
Named
Callbacks
<<protocol>>
context
<<protocol>>
Repo
Enable Labs @mark_menard
# app/controllers/pages_controller.rb
def create
run(Create, params[:wiki_id], page_params) do |on|
on.success { |page|
redirect_to [page.wiki, page],
notice: "#{page.name} created"
}
on.failure { |wiki, page|
render :new
}
end
end
Runner
Named
Callbacks
<<protocol>>
context
<<protocol>>
Repo
Enable Labs @mark_menard
# app/controllers/pages_controller.rb
def create
run(Create, params[:wiki_id], page_params) do |on|
on.success { |page|
redirect_to [page.wiki, page],
notice: "#{page.name} created"
}
on.failure { |wiki, page|
render :new
}
end
end
Runner
Named
Callbacks
<<protocol>>
context
<<protocol>>
Repo
Enable Labs @mark_menard
# app/controllers/pages_controller.rb
def create
run(Create, params[:wiki_id], page_params) do |on|
on.success { |page|
redirect_to [page.wiki, page],
notice: "#{page.name} created"
}
on.failure { |wiki, page|
render :new
}
end
end
Runner
Named
Callbacks
<<protocol>>
context
<<protocol>>
Repo
Enable Labs @mark_menard
# app/runners/runner.rb
class Runner
attr_reader :context
!
def initialize(context)
@callbacks = NamedCallbacks.new
@context = context
yield(@callbacks) if block_given?
end
!
def repo
context.repo
end
!
def success(*args)
callback(:success, *args)
end
!
def failure(*args)
callback(:failure, *args)
end
!
def callback(name, *args)
@callbacks.call(name, *args)
args
end
end
# app/controllers/pages_controller.rb
def create
run(Create, params[:wiki_id], page_params) do |on|
on.success { |page|
redirect_to [page.wiki, page],
notice: "#{page.name} created"
}
on.failure { |wiki, page|
render :new
}
end
end
Runner
Named
Callbacks
<<protocol>>
context
<<protocol>>
Repo
Enable Labs @mark_menard
# app/runners/runner.rb
class Runner
attr_reader :context
!
def initialize(context)
@callbacks = NamedCallbacks.new
@context = context
yield(@callbacks) if block_given?
end
!
def repo
context.repo
end
!
def success(*args)
callback(:success, *args)
end
!
def failure(*args)
callback(:failure, *args)
end
!
def callback(name, *args)
@callbacks.call(name, *args)
args
end
end
# app/controllers/pages_controller.rb
def create
run(Create, params[:wiki_id], page_params) do |on|
on.success { |page|
redirect_to [page.wiki, page],
notice: "#{page.name} created"
}
on.failure { |wiki, page|
render :new
}
end
end
Runner
Named
Callbacks
<<protocol>>
context
<<protocol>>
Repo
Enable Labs @mark_menard
# app/runners/runner.rb
class Runner
attr_reader :context
!
def initialize(context)
@callbacks = NamedCallbacks.new
@context = context
yield(@callbacks) if block_given?
end
!
# …
end
# app/runners/named_callbacks.rb
class NamedCallbacks
def initialize
@callbacks = {}
end
!
def method_missing(sym, *args, &block)
@callbacks[sym] = block
end
!
# …
end
# app/controllers/pages_controller.rb
def create
run(Create, params[:wiki_id], page_params) do |on|
on.success { |page|
redirect_to [page.wiki, page],
notice: "#{page.name} created"
}
on.failure { |wiki, page|
render :new
}
end
end
Enable Labs @mark_menard
# app/runners/runner.rb
class Runner
attr_reader :context
!
def initialize(context)
@callbacks = NamedCallbacks.new
@context = context
yield(@callbacks) if block_given?
end
!
# …
end
# app/runners/named_callbacks.rb
class NamedCallbacks
def initialize
@callbacks = {}
end
!
def method_missing(sym, *args, &block)
@callbacks[sym] = block
end
!
# …
end
# app/controllers/pages_controller.rb
def create
run(Create, params[:wiki_id], page_params) do |on|
on.success { |page|
redirect_to [page.wiki, page],
notice: "#{page.name} created"
}
on.failure { |wiki, page|
render :new
}
end
end
Enable Labs @mark_menard
# app/runners/named_callbacks.rb
class NamedCallbacks
def initialize
@callbacks = {}
end
!
def method_missing(sym, *args, &block)
@callbacks[sym] = block
end
!
# …
end
# app/controllers/pages_controller.rb
def create
run(Create, params[:wiki_id], page_params) do |on|
on.success { |page|
redirect_to [page.wiki, page],
notice: "#{page.name} created"
}
on.failure { |wiki, page|
render :new
}
end
end
Enable Labs @mark_menard
# app/runners/named_callbacks.rb
class NamedCallbacks
def initialize
@callbacks = {}
end
!
def method_missing(sym, *args, &block)
@callbacks[sym] = block
end
!
# …
end
# app/controllers/pages_controller.rb
def create
run(Create, params[:wiki_id], page_params) do |on|
on.success { |page|
redirect_to [page.wiki, page],
notice: "#{page.name} created"
}
on.failure { |wiki, page|
render :new
}
end
end
Enable Labs @mark_menard
# app/runners/named_callbacks.rb
class NamedCallbacks
def initialize
@callbacks = {}
end
!
def method_missing(sym, *args, &block)
@callbacks[sym] = block
end
!
# …
end
# app/controllers/pages_controller.rb
def create
run(Create, params[:wiki_id], page_params) do |on|
on.success { |page|
redirect_to [page.wiki, page],
notice: "#{page.name} created"
}
on.failure { |wiki, page|
render :new
}
end
end
Enable Labs @mark_menard
# app/controllers/pages_controller.rb
def create
run(Create, params[:wiki_id], page_params) do |on|
on.success { |page|
redirect_to [page.wiki, page],
notice: "#{page.name} created"
}
on.failure { |wiki, page|
render :new
}
end
end
Weirich Block Style
Enable Labs @mark_menard
# app/controllers/pages_controller.rb
def create
run(Create, params[:wiki_id], page_params) do |on|
on.success { |page|
redirect_to [page.wiki, page],
notice: "#{page.name} created"
}
on.failure { |wiki, page|
render :new
}
end
end
# app/controllers/pages_controller.rb
def create
run(Create, params[:wiki_id], page_params) do |on|
on.success { |page|
redirect_to [page.wiki, page],
notice: "#{page.name} created"
}
on.failure { |wiki, page|
render :new
}
end
end
Weirich Block Style
Enable Labs @mark_menard
Some Lessons
Enable Labs @mark_menard
Repositories
Enable Labs @mark_menard
Domain Rails
Enable Labs @mark_menard
Enable Labs @mark_menard
Enable Labs @mark_menard
Action
Controller ::
Base
ActiveRecord
:: Base
Page
Controller
Application
Controller
Page
Wiki
Create Page
Runner
<<protocol>>
Repo
Repo
<<protocol>>
context
Enable Labs @mark_menard
Action
Controller ::
Base
ActiveRecord
:: Base
Page
Controller
Application
Controller
Page
Wiki
Create Page
Runner
<<protocol>>
Repo
Repo
<<protocol>>
context
Domain
Enable Labs @mark_menard
Action
Controller ::
Base
ActiveRecord
:: Base
Page
Controller
Application
Controller
Page
Wiki
Create Page
Runner
<<protocol>>
Repo
Repo
<<protocol>>
context
Domain
Enable Labs @mark_menard
Action
Controller ::
Base
ActiveRecord
:: Base
Page
Controller
Application
Controller
Page
Wiki
Create Page
Runner
<<protocol>>
Repo
Repo
<<protocol>>
context
Domain
Enable Labs @mark_menard
# app/services/wiki_repository.rb
class WikiRepository
include Repo::UserMethods
include Repo::WikiMethods
include Repo::PageMethods
include Repo::PermissionMethods
end
Enable Labs @mark_menard
# app/services/repo/page_methods.rb
module PageMethods
def find_wiki_page(wiki_id, page_id)
wiki = Wiki.find(wiki_id)
page = wiki.pages.find(page_id)
!
# …
end
!
# …
!
def save_page(page)
page.data.save
end
!
# …
end
Enable Labs @mark_menard
Domain
Enable Labs @mark_menard
Biz Objects
Enable Labs @mark_menard
Action
Controller ::
Base
ActiveRecord
:: Base
Page
Controller
Application
Controller
Page
Wiki
Create Page
Runner
<<protocol>>
Repo
Repo
<<protocol>>
context
Domain
Enable Labs @mark_menard
Biz Model
ActiveRecord
:: Base
Simple
Delegator
Enable Labs @mark_menard
# app/models/biz/model.rb
module Biz
class Model < SimpleDelegator
include BlockActiveRecord
!
def data
datum = self
while datum.biz?
datum = datum.__getobj__
end
datum
end
!
def ==(other)
if other.respond_to?(:data)
data == other.data
else
data == other
end
end
def biz?
true
end
!
def class
data.class
end
!
def self.wrap(model)
model ? new(model) : nil
end
!
def self.wraps(models)
models.map { |model| wrap(model) }
end
!
end
end
Enable Labs @mark_menard
# app/models/biz/model.rb
module Biz
class Model < SimpleDelegator
include BlockActiveRecord
!
def data
datum = self
while datum.biz?
datum = datum.__getobj__
end
datum
end
!
def ==(other)
if other.respond_to?(:data)
data == other.data
else
data == other
end
end
def biz?
true
end
!
def class
data.class
end
!
def self.wrap(model)
model ? new(model) : nil
end
!
def self.wraps(models)
models.map { |model| wrap(model) }
end
!
end
end
Enable Labs @mark_menard
# app/models/biz/model.rb
module Biz
class Model < SimpleDelegator
include BlockActiveRecord
!
def data
datum = self
while datum.biz?
datum = datum.__getobj__
end
datum
end
!
def ==(other)
if other.respond_to?(:data)
data == other.data
else
data == other
end
end
def biz?
true
end
!
def class
data.class
end
!
def self.wrap(model)
model ? new(model) : nil
end
!
def self.wraps(models)
models.map { |model| wrap(model) }
end
!
end
end
Enable Labs @mark_menard
# app/models/biz/model.rb
module Biz
class Model < SimpleDelegator
include BlockActiveRecord
!
def data
datum = self
while datum.biz?
datum = datum.__getobj__
end
datum
end
!
def ==(other)
if other.respond_to?(:data)
data == other.data
else
data == other
end
end
def biz?
true
end
!
def class
data.class
end
!
def self.wrap(model)
model ? new(model) : nil
end
!
def self.wraps(models)
models.map { |model| wrap(model) }
end
!
end
end
Enable Labs @mark_menard
# app/models/biz/model.rb
module Biz
class Model < SimpleDelegator
include BlockActiveRecord
!
def data
datum = self
while datum.biz?
datum = datum.__getobj__
end
datum
end
!
def ==(other)
if other.respond_to?(:data)
data == other.data
else
data == other
end
end
def biz?
true
end
!
def class
data.class
end
!
def self.wrap(model)
model ? new(model) : nil
end
!
def self.wraps(models)
models.map { |model| wrap(model) }
end
!
end
end
Enable Labs @mark_menard
# app/models/biz/model.rb
module Biz
class Model < SimpleDelegator
include BlockActiveRecord
!
def data
datum = self
while datum.biz?
datum = datum.__getobj__
end
datum
end
!
def ==(other)
if other.respond_to?(:data)
data == other.data
else
data == other
end
end
def biz?
true
end
!
def class
data.class
end
!
def self.wrap(model)
model ? new(model) : nil
end
!
def self.wraps(models)
models.map { |model| wrap(model) }
end
!
end
end
Enable Labs @mark_menard
# app/services/repo/page_methods.rb
module PageMethods
def find_wiki_page(wiki_id, page_id)
wiki = Wiki.find(wiki_id)
page = wiki.pages.find(page_id)
Biz::Page.wrap(page)
end
!
# …
!
def save_page(page)
page.data.save
end
!
# …
end
Enable Labs @mark_menard
# app/services/repo/page_methods.rb
module PageMethods
def find_wiki_page(wiki_id, page_id)
wiki = Wiki.find(wiki_id)
page = wiki.pages.find(page_id)
Biz::Page.wrap(page)
end
!
# …
!
def save_page(page)
page.data.save
end
!
# …
end
Enable Labs @mark_menard
module Biz
class Page < Model
def wiki
Biz::Wiki.wrap(super)
end
!
def html_content(context)
Kramdown::Document.new(referenced_content(context)).to_html
end
!
def referenced_content(context)
content.gsub(/(([A-Z][a-z0-9]+){2,})/) { |page_name|
if wiki.page?(context.repo, page_name)
"[#{page_name}](#{context.named_page_path(wiki.name,page_name)})"
elsif context.current_user.can_write?(wiki)
"#{page_name}[?](#{context.new_named_page_path(wiki.name, page_name)})"
else
page_name
end
}
end
end
end
Enable Labs @mark_menard
module Biz
class Page < Model
def wiki
Biz::Wiki.wrap(super)
end
!
def html_content(context)
Kramdown::Document.new(referenced_content(context)).to_html
end
!
def referenced_content(context)
content.gsub(/(([A-Z][a-z0-9]+){2,})/) { |page_name|
if wiki.page?(context.repo, page_name)
"[#{page_name}](#{context.named_page_path(wiki.name,page_name)})"
elsif context.current_user.can_write?(wiki)
"#{page_name}[?](#{context.new_named_page_path(wiki.name, page_name)})"
else
page_name
end
}
end
end
end
Enable Labs @mark_menard
Action
Controller ::
Base
ActiveRecord
:: Base
Page
Controller
Application
Controller
Some Model
Runner
Repo
Biz Model
<< wraps >>
Enable Labs @mark_menard
Action
Controller ::
Base
ActiveRecord
:: Base
Page
Controller
Application
Controller
Some Model
Runner
Repo
Biz Model
<< wraps >>
Enable Labs @mark_menard
More Lessons
Enable Labs @mark_menard
Why?
Enable Labs @mark_menard
Isolated Business Logic
Enable Labs @mark_menard
Incremental Approach
Enable Labs @mark_menard
Fast Tests
Enable Labs @mark_menard
$ time rspec spec/runners spec/models/biz (git)-[master]
......................................................................................................
!
Finished in 0.17573 seconds
102 examples, 0 failures
rspec spec/runners spec/models/biz 0.61s user 0.07s system 99% cpu 0.683 total
Enable Labs @mark_menard
Should we decouple?
Enable Labs @mark_menard
http://www.flickr.com/photos/dwortlehock/
Thanks for Everything Jim!
Enable Labs @mark_menard
Start Today
http://www.enablelabs.com/
mark@enablelabs.com
866-895-8189
Enable Labs
@mark_menard

Contenu connexe

Tendances

Enemy of the state
Enemy of the stateEnemy of the state
Enemy of the state
Mike North
 
Enter the app era with ruby on rails (rubyday)
Enter the app era with ruby on rails (rubyday)Enter the app era with ruby on rails (rubyday)
Enter the app era with ruby on rails (rubyday)
Matteo Collina
 
Client Side Applications with WP-API WordPress - WCMTL 2015
Client Side Applications with WP-API WordPress - WCMTL 2015Client Side Applications with WP-API WordPress - WCMTL 2015
Client Side Applications with WP-API WordPress - WCMTL 2015
Roy Sivan
 

Tendances (20)

Developing Modern Java Web Applications with Java EE 7 and AngularJS
Developing Modern Java Web Applications with Java EE 7 and AngularJSDeveloping Modern Java Web Applications with Java EE 7 and AngularJS
Developing Modern Java Web Applications with Java EE 7 and AngularJS
 
Using ArcGIS Server with Ruby on Rails
Using ArcGIS Server with Ruby on RailsUsing ArcGIS Server with Ruby on Rails
Using ArcGIS Server with Ruby on Rails
 
Enemy of the state
Enemy of the stateEnemy of the state
Enemy of the state
 
Poisoning Google images
Poisoning Google imagesPoisoning Google images
Poisoning Google images
 
Play Framework workshop: full stack java web app
Play Framework workshop: full stack java web appPlay Framework workshop: full stack java web app
Play Framework workshop: full stack java web app
 
Building WordPress Client Side Applications with WP and WP-API - #wcmia
Building WordPress Client Side Applications with WP and WP-API - #wcmiaBuilding WordPress Client Side Applications with WP and WP-API - #wcmia
Building WordPress Client Side Applications with WP and WP-API - #wcmia
 
Enter the app era with ruby on rails (rubyday)
Enter the app era with ruby on rails (rubyday)Enter the app era with ruby on rails (rubyday)
Enter the app era with ruby on rails (rubyday)
 
How to build Client Side Applications with WordPress and WP-API | #wcmia
How to build Client Side Applications with WordPress and WP-API | #wcmiaHow to build Client Side Applications with WordPress and WP-API | #wcmia
How to build Client Side Applications with WordPress and WP-API | #wcmia
 
Story Driven Development With Cucumber
Story Driven Development With CucumberStory Driven Development With Cucumber
Story Driven Development With Cucumber
 
Merb Slices
Merb SlicesMerb Slices
Merb Slices
 
Developing, Testing and Scaling with Apache Camel - UberConf 2015
Developing, Testing and Scaling with Apache Camel - UberConf 2015Developing, Testing and Scaling with Apache Camel - UberConf 2015
Developing, Testing and Scaling with Apache Camel - UberConf 2015
 
CPAN Dependency Heaven
CPAN Dependency HeavenCPAN Dependency Heaven
CPAN Dependency Heaven
 
Introduction to Retrofit
Introduction to RetrofitIntroduction to Retrofit
Introduction to Retrofit
 
Code diving in Ruby and Rails
Code diving in Ruby and RailsCode diving in Ruby and Rails
Code diving in Ruby and Rails
 
Hosting Your Own OTA Update Service
Hosting Your Own OTA Update ServiceHosting Your Own OTA Update Service
Hosting Your Own OTA Update Service
 
Nightwatch at Tilt
Nightwatch at TiltNightwatch at Tilt
Nightwatch at Tilt
 
No callbacks, No Threads - Cooperative web servers in Ruby 1.9
No callbacks, No Threads - Cooperative web servers in Ruby 1.9No callbacks, No Threads - Cooperative web servers in Ruby 1.9
No callbacks, No Threads - Cooperative web servers in Ruby 1.9
 
20160905 - BrisJS - nightwatch testing
20160905 - BrisJS - nightwatch testing20160905 - BrisJS - nightwatch testing
20160905 - BrisJS - nightwatch testing
 
Client Side Applications with WP-API WordPress - WCMTL 2015
Client Side Applications with WP-API WordPress - WCMTL 2015Client Side Applications with WP-API WordPress - WCMTL 2015
Client Side Applications with WP-API WordPress - WCMTL 2015
 
Intro to Rails
Intro to RailsIntro to Rails
Intro to Rails
 

En vedette

Conference of Grand Masters Tech Talk 2013
Conference of Grand Masters Tech Talk 2013Conference of Grand Masters Tech Talk 2013
Conference of Grand Masters Tech Talk 2013
Mark Menard
 

En vedette (7)

Small Code - Ruby on Ales 2014
Small Code - Ruby on Ales 2014Small Code - Ruby on Ales 2014
Small Code - Ruby on Ales 2014
 
Write Small Things (Code)
Write Small Things (Code)Write Small Things (Code)
Write Small Things (Code)
 
Let's Do Some Upfront Design - WindyCityRails 2014
Let's Do Some Upfront Design - WindyCityRails 2014Let's Do Some Upfront Design - WindyCityRails 2014
Let's Do Some Upfront Design - WindyCityRails 2014
 
Conference of Grand Masters Tech Talk 2013
Conference of Grand Masters Tech Talk 2013Conference of Grand Masters Tech Talk 2013
Conference of Grand Masters Tech Talk 2013
 
Small Code - RailsConf 2014
Small Code - RailsConf 2014Small Code - RailsConf 2014
Small Code - RailsConf 2014
 
JRuby 6 Years in Production
JRuby 6 Years in ProductionJRuby 6 Years in Production
JRuby 6 Years in Production
 
Startup Lessons Learned
Startup Lessons LearnedStartup Lessons Learned
Startup Lessons Learned
 

Similaire à A Tour of Wyriki

浜松Rails3道場 其の四 View編
浜松Rails3道場 其の四 View編浜松Rails3道場 其の四 View編
浜松Rails3道場 其の四 View編
Masakuni Kato
 
Ruby conf 2011, Create your own rails framework
Ruby conf 2011, Create your own rails frameworkRuby conf 2011, Create your own rails framework
Ruby conf 2011, Create your own rails framework
Pankaj Bhageria
 
Rails 3: Dashing to the Finish
Rails 3: Dashing to the FinishRails 3: Dashing to the Finish
Rails 3: Dashing to the Finish
Yehuda Katz
 
Rails 3 overview
Rails 3 overviewRails 3 overview
Rails 3 overview
Yehuda Katz
 
An introduction-to-ruby-on-rails
An introduction-to-ruby-on-railsAn introduction-to-ruby-on-rails
An introduction-to-ruby-on-rails
vinicorp
 
An Introduction to Ruby on Rails 20100506
An Introduction to Ruby on Rails 20100506An Introduction to Ruby on Rails 20100506
An Introduction to Ruby on Rails 20100506
Vu Hung Nguyen
 
JRuby + Rails = Awesome Java Web Framework at Jfokus 2011
JRuby + Rails = Awesome Java Web Framework at Jfokus 2011JRuby + Rails = Awesome Java Web Framework at Jfokus 2011
JRuby + Rails = Awesome Java Web Framework at Jfokus 2011
Nick Sieger
 
Single Page Web Applications with CoffeeScript, Backbone and Jasmine
Single Page Web Applications with CoffeeScript, Backbone and JasmineSingle Page Web Applications with CoffeeScript, Backbone and Jasmine
Single Page Web Applications with CoffeeScript, Backbone and Jasmine
Paulo Ragonha
 

Similaire à A Tour of Wyriki (20)

Pourquoi ruby et rails déchirent
Pourquoi ruby et rails déchirentPourquoi ruby et rails déchirent
Pourquoi ruby et rails déchirent
 
Rails Engine | Modular application
Rails Engine | Modular applicationRails Engine | Modular application
Rails Engine | Modular application
 
浜松Rails3道場 其の四 View編
浜松Rails3道場 其の四 View編浜松Rails3道場 其の四 View編
浜松Rails3道場 其の四 View編
 
Ruby on Rails survival guide of an aged Java developer
Ruby on Rails survival guide of an aged Java developerRuby on Rails survival guide of an aged Java developer
Ruby on Rails survival guide of an aged Java developer
 
Building web framework with Rack
Building web framework with RackBuilding web framework with Rack
Building web framework with Rack
 
Ruby on Rails - Introduction
Ruby on Rails - IntroductionRuby on Rails - Introduction
Ruby on Rails - Introduction
 
Ruby conf 2011, Create your own rails framework
Ruby conf 2011, Create your own rails frameworkRuby conf 2011, Create your own rails framework
Ruby conf 2011, Create your own rails framework
 
Rails::Engine
Rails::EngineRails::Engine
Rails::Engine
 
JRuby, Ruby, Rails and You on the Cloud
JRuby, Ruby, Rails and You on the CloudJRuby, Ruby, Rails and You on the Cloud
JRuby, Ruby, Rails and You on the Cloud
 
Tdc 2013 - Ecossistema Ruby
Tdc 2013 - Ecossistema RubyTdc 2013 - Ecossistema Ruby
Tdc 2013 - Ecossistema Ruby
 
Rails 3: Dashing to the Finish
Rails 3: Dashing to the FinishRails 3: Dashing to the Finish
Rails 3: Dashing to the Finish
 
Ruby on Rails at PROMPT ISEL '11
Ruby on Rails at PROMPT ISEL '11Ruby on Rails at PROMPT ISEL '11
Ruby on Rails at PROMPT ISEL '11
 
SproutCore and the Future of Web Apps
SproutCore and the Future of Web AppsSproutCore and the Future of Web Apps
SproutCore and the Future of Web Apps
 
RxSwift to Combine
RxSwift to CombineRxSwift to Combine
RxSwift to Combine
 
Rails 3 overview
Rails 3 overviewRails 3 overview
Rails 3 overview
 
An introduction-to-ruby-on-rails
An introduction-to-ruby-on-railsAn introduction-to-ruby-on-rails
An introduction-to-ruby-on-rails
 
An Introduction to Ruby on Rails 20100506
An Introduction to Ruby on Rails 20100506An Introduction to Ruby on Rails 20100506
An Introduction to Ruby on Rails 20100506
 
JRuby + Rails = Awesome Java Web Framework at Jfokus 2011
JRuby + Rails = Awesome Java Web Framework at Jfokus 2011JRuby + Rails = Awesome Java Web Framework at Jfokus 2011
JRuby + Rails = Awesome Java Web Framework at Jfokus 2011
 
Spring into rails
Spring into railsSpring into rails
Spring into rails
 
Single Page Web Applications with CoffeeScript, Backbone and Jasmine
Single Page Web Applications with CoffeeScript, Backbone and JasmineSingle Page Web Applications with CoffeeScript, Backbone and Jasmine
Single Page Web Applications with CoffeeScript, Backbone and Jasmine
 

Plus de Mark Menard (8)

Mobile Platforms and App Development
Mobile Platforms and App DevelopmentMobile Platforms and App Development
Mobile Platforms and App Development
 
Ruby on Rails Training - Module 2
Ruby on Rails Training - Module 2Ruby on Rails Training - Module 2
Ruby on Rails Training - Module 2
 
Ruby on Rails Training - Module 1
Ruby on Rails Training - Module 1Ruby on Rails Training - Module 1
Ruby on Rails Training - Module 1
 
Introduction to Ruby
Introduction to RubyIntroduction to Ruby
Introduction to Ruby
 
Intro to Rails ActiveRecord
Intro to Rails ActiveRecordIntro to Rails ActiveRecord
Intro to Rails ActiveRecord
 
Behavior Driven Development with Rails
Behavior Driven Development with RailsBehavior Driven Development with Rails
Behavior Driven Development with Rails
 
Intro to Ruby on Rails
Intro to Ruby on RailsIntro to Ruby on Rails
Intro to Ruby on Rails
 
JRuby in a Java World
JRuby in a Java WorldJRuby in a Java World
JRuby in a Java World
 

Dernier

+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
?#DUbAI#??##{{(☎️+971_581248768%)**%*]'#abortion pills for sale in dubai@
 

Dernier (20)

Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024
 
AXA XL - Insurer Innovation Award Americas 2024
AXA XL - Insurer Innovation Award Americas 2024AXA XL - Insurer Innovation Award Americas 2024
AXA XL - Insurer Innovation Award Americas 2024
 
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin WoodPolkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
 
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
 
DBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor PresentationDBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor Presentation
 
ICT role in 21st century education and its challenges
ICT role in 21st century education and its challengesICT role in 21st century education and its challenges
ICT role in 21st century education and its challenges
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdf
 
Apidays Singapore 2024 - Scalable LLM APIs for AI and Generative AI Applicati...
Apidays Singapore 2024 - Scalable LLM APIs for AI and Generative AI Applicati...Apidays Singapore 2024 - Scalable LLM APIs for AI and Generative AI Applicati...
Apidays Singapore 2024 - Scalable LLM APIs for AI and Generative AI Applicati...
 
"I see eyes in my soup": How Delivery Hero implemented the safety system for ...
"I see eyes in my soup": How Delivery Hero implemented the safety system for ..."I see eyes in my soup": How Delivery Hero implemented the safety system for ...
"I see eyes in my soup": How Delivery Hero implemented the safety system for ...
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
 
MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024
 
GenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdfGenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdf
 
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
 
A Beginners Guide to Building a RAG App Using Open Source Milvus
A Beginners Guide to Building a RAG App Using Open Source MilvusA Beginners Guide to Building a RAG App Using Open Source Milvus
A Beginners Guide to Building a RAG App Using Open Source Milvus
 
Real Time Object Detection Using Open CV
Real Time Object Detection Using Open CVReal Time Object Detection Using Open CV
Real Time Object Detection Using Open CV
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Script
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
 
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
 
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, AdobeApidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
 

A Tour of Wyriki

  • 1. Enable Labs @mark_menard A Tour of Wyriki Mark Menard Ruby Nation! June 7, 2014 @mark_menard ! Enable Labs
  • 7. Enable Labs @mark_menard The Wyriki Domain Page Wiki * 1 Create Wiki Create Page Update Page Create User Loged In User Anony mous User
  • 8. Enable Labs @mark_menard Business Logic ActiveRecord ActionPack Controllers MySQL MongoDB PostgreSQL Redis Sidekiq Resque What was Jim trying to accomplish?
  • 12. Enable Labs @mark_menard Create Page Loged In User Action Controller :: Base ActiveRecord :: Base Pages Controller Application Controller Page Wiki
  • 13. Enable Labs @mark_menard Create Page Loged In User Action Controller :: Base ActiveRecord :: Base Pages Controller Application Controller Page Wiki
  • 14. Enable Labs @mark_menard Create Page Loged In User Action Controller :: Base ActiveRecord :: Base Pages Controller Application Controller Page Wiki
  • 15. Enable Labs @mark_menard # app/controllers/pages_controller.rb def create @wiki = Wiki.find(params[:wiki_id]) @page = @wiki.pages.new(page_params) if @page.save redirect_to [@wiki, @page], notice: "#{@page.name} created" else render :new end end
  • 17. Enable Labs @mark_menard Runners class Runner attr_reader :context ! def initialize(context) @callbacks = NamedCallbacks.new @context = context yield(@callbacks) if block_given? end ! def repo context.repo end ! def success(*args) callback(:success, *args) end ! def failure(*args) callback(:failure, *args) end ! def callback(name, *args) @callbacks.call(name, *args) args end end class Model < SimpleDelegator include BlockActiveRecord ! def data datum = self while datum.biz? datum = datum.__getobj__ end datum end ! def ==(other) if other.respond_to?(:data) data == other.data else data == other end end ! def biz? true end ! def class data.class end ! def self.wrap(model) model ? new(model) : nil end ! def self.wraps(models) models.map { |model| wrap(model) } end !end Business Models Repositories module UserMethods def all_users Biz::User.wraps(User.all_users) end ! def new_user(attrs={}) Biz::User.wrap(User.new(attrs)) end ! def find_user(user_id) Biz::User.wrap(User.find(user_id)) end ! def save_user(user) user.data.save end ! def update_user(user, attrs) user.data.update_attributes(attrs) end ! def destroy_user(user_id) User.destroy(user_id) end end
  • 18. Enable Labs @mark_menard Action Controller :: Base ActiveRecord :: Base Page Controller Application Controller Page Wiki Create Page Runner <<protocol>> Repo Repo <<protocol>> context <<protocol>> Biz Page <<protocol>> Biz Wiki Biz::Wiki Biz::Page <<protocol>> Wiki Data <<protocol>> Page Data <<wraps>> <<wraps>>
  • 19. Enable Labs @mark_menard Action Controller :: Base ActiveRecord :: Base Page Controller Application Controller Some Model Runner Repo Biz Model << wraps >> << gets and saves stuff >>
  • 20. Enable Labs @mark_menard Action Controller :: Base ActiveRecord :: Base Page Controller Application Controller Some Model Runner Repo Biz Model << wraps >> << gets and saves stuff >>
  • 24. Enable Labs @mark_menard Action Controller :: Base ActiveRecord :: Base Page Controller Application Controller Page Wiki Create Page Runner <<protocol>> context Rails Not Rails Create Page Loged In User
  • 25. Enable Labs @mark_menard This is the ! Domain
  • 26. Enable Labs @mark_menard This is the ! Domain This is Rails
  • 27. Enable Labs @mark_menard This is our Context.
  • 28. Enable Labs @mark_menard # app/controllers/page_controller.rb def create run(Create, params[:wiki_id], page_params) do |on| on.success { |page| redirect_to [page.wiki, page], notice: "#{page.name} created" } on.failure { |wiki, page| render :new } end end
  • 29. Enable Labs @mark_menard # app/controllers/page_controller.rb def create run(Create, params[:wiki_id], page_params) do |on| on.success { |page| redirect_to [page.wiki, page], notice: "#{page.name} created" } on.failure { |wiki, page| render :new } end end
  • 30. Enable Labs @mark_menard # app/controllers/page_controller.rb def create run(Create, params[:wiki_id], page_params) do |on| on.success { |page| redirect_to [page.wiki, page], notice: "#{page.name} created" } on.failure { |wiki, page| render :new } end end
  • 31. Enable Labs @mark_menard # app/runners/page_runners.rb class Create < Runner def run(wiki_id, page_params) wiki = Wiki.find(params[:wiki_id]) page = wiki.pages.new(page_params) if page.save success(page) else failure(wiki, page) end end end
  • 32. Enable Labs @mark_menard # app/runners/page_runners.rb class Create < Runner def run(wiki_id, page_params) wiki = Wiki.find(params[:wiki_id]) page = wiki.pages.new(page_params) if page.save success(page) else failure(wiki, page) end end end # app/controllers/page_controller.rb def create Create.new(self, params[:wiki_id], page_params).run do |on| on.success { |page| redirect_to [page.wiki, page], notice: "#{page.name} created" } on.failure { |wiki, page| render :new } end end
  • 33. Enable Labs @mark_menard # app/runners/page_runners.rb class Create < Runner def run(wiki_id, page_params) wiki = Wiki.find(params[:wiki_id]) page = wiki.pages.new(page_params) if page.save success(page) else failure(wiki, page) end end end # app/controllers/page_controller.rb def create Create.new(self, params[:wiki_id], page_params).run do |on| on.success { |page| redirect_to [page.wiki, page], notice: "#{page.name} created" } on.failure { |wiki, page| render :new } end end
  • 34. Enable Labs @mark_menard Action Controller :: Base ActiveRecord :: Base Page Controller Application Controller Page Wiki Create Page Runner <<protocol>> context Rails Not Rails Create Page Loged In User
  • 35. Enable Labs @mark_menard Enough Architecture! ! What about the Ruby!! ! How did Jim actually ! do the callbacks and the runners?
  • 37. Enable Labs @mark_menard # app/controllers/pages_controller.rb def create run(Create, params[:wiki_id], page_params) do |on| on.success { |page| redirect_to [page.wiki, page], notice: "#{page.name} created" } on.failure { |wiki, page| render :new } end end Runner Named Callbacks <<protocol>> context <<protocol>> Repo
  • 38. Enable Labs @mark_menard # app/controllers/pages_controller.rb def create run(Create, params[:wiki_id], page_params) do |on| on.success { |page| redirect_to [page.wiki, page], notice: "#{page.name} created" } on.failure { |wiki, page| render :new } end end Runner Named Callbacks <<protocol>> context <<protocol>> Repo
  • 39. Enable Labs @mark_menard # app/controllers/pages_controller.rb def create run(Create, params[:wiki_id], page_params) do |on| on.success { |page| redirect_to [page.wiki, page], notice: "#{page.name} created" } on.failure { |wiki, page| render :new } end end Runner Named Callbacks <<protocol>> context <<protocol>> Repo
  • 40. Enable Labs @mark_menard # app/runners/runner.rb class Runner attr_reader :context ! def initialize(context) @callbacks = NamedCallbacks.new @context = context yield(@callbacks) if block_given? end ! def repo context.repo end ! def success(*args) callback(:success, *args) end ! def failure(*args) callback(:failure, *args) end ! def callback(name, *args) @callbacks.call(name, *args) args end end # app/controllers/pages_controller.rb def create run(Create, params[:wiki_id], page_params) do |on| on.success { |page| redirect_to [page.wiki, page], notice: "#{page.name} created" } on.failure { |wiki, page| render :new } end end Runner Named Callbacks <<protocol>> context <<protocol>> Repo
  • 41. Enable Labs @mark_menard # app/runners/runner.rb class Runner attr_reader :context ! def initialize(context) @callbacks = NamedCallbacks.new @context = context yield(@callbacks) if block_given? end ! def repo context.repo end ! def success(*args) callback(:success, *args) end ! def failure(*args) callback(:failure, *args) end ! def callback(name, *args) @callbacks.call(name, *args) args end end # app/controllers/pages_controller.rb def create run(Create, params[:wiki_id], page_params) do |on| on.success { |page| redirect_to [page.wiki, page], notice: "#{page.name} created" } on.failure { |wiki, page| render :new } end end Runner Named Callbacks <<protocol>> context <<protocol>> Repo
  • 42. Enable Labs @mark_menard # app/runners/runner.rb class Runner attr_reader :context ! def initialize(context) @callbacks = NamedCallbacks.new @context = context yield(@callbacks) if block_given? end ! # … end # app/runners/named_callbacks.rb class NamedCallbacks def initialize @callbacks = {} end ! def method_missing(sym, *args, &block) @callbacks[sym] = block end ! # … end # app/controllers/pages_controller.rb def create run(Create, params[:wiki_id], page_params) do |on| on.success { |page| redirect_to [page.wiki, page], notice: "#{page.name} created" } on.failure { |wiki, page| render :new } end end
  • 43. Enable Labs @mark_menard # app/runners/runner.rb class Runner attr_reader :context ! def initialize(context) @callbacks = NamedCallbacks.new @context = context yield(@callbacks) if block_given? end ! # … end # app/runners/named_callbacks.rb class NamedCallbacks def initialize @callbacks = {} end ! def method_missing(sym, *args, &block) @callbacks[sym] = block end ! # … end # app/controllers/pages_controller.rb def create run(Create, params[:wiki_id], page_params) do |on| on.success { |page| redirect_to [page.wiki, page], notice: "#{page.name} created" } on.failure { |wiki, page| render :new } end end
  • 44. Enable Labs @mark_menard # app/runners/named_callbacks.rb class NamedCallbacks def initialize @callbacks = {} end ! def method_missing(sym, *args, &block) @callbacks[sym] = block end ! # … end # app/controllers/pages_controller.rb def create run(Create, params[:wiki_id], page_params) do |on| on.success { |page| redirect_to [page.wiki, page], notice: "#{page.name} created" } on.failure { |wiki, page| render :new } end end
  • 45. Enable Labs @mark_menard # app/runners/named_callbacks.rb class NamedCallbacks def initialize @callbacks = {} end ! def method_missing(sym, *args, &block) @callbacks[sym] = block end ! # … end # app/controllers/pages_controller.rb def create run(Create, params[:wiki_id], page_params) do |on| on.success { |page| redirect_to [page.wiki, page], notice: "#{page.name} created" } on.failure { |wiki, page| render :new } end end
  • 46. Enable Labs @mark_menard # app/runners/named_callbacks.rb class NamedCallbacks def initialize @callbacks = {} end ! def method_missing(sym, *args, &block) @callbacks[sym] = block end ! # … end # app/controllers/pages_controller.rb def create run(Create, params[:wiki_id], page_params) do |on| on.success { |page| redirect_to [page.wiki, page], notice: "#{page.name} created" } on.failure { |wiki, page| render :new } end end
  • 47. Enable Labs @mark_menard # app/controllers/pages_controller.rb def create run(Create, params[:wiki_id], page_params) do |on| on.success { |page| redirect_to [page.wiki, page], notice: "#{page.name} created" } on.failure { |wiki, page| render :new } end end Weirich Block Style
  • 48. Enable Labs @mark_menard # app/controllers/pages_controller.rb def create run(Create, params[:wiki_id], page_params) do |on| on.success { |page| redirect_to [page.wiki, page], notice: "#{page.name} created" } on.failure { |wiki, page| render :new } end end # app/controllers/pages_controller.rb def create run(Create, params[:wiki_id], page_params) do |on| on.success { |page| redirect_to [page.wiki, page], notice: "#{page.name} created" } on.failure { |wiki, page| render :new } end end Weirich Block Style
  • 54. Enable Labs @mark_menard Action Controller :: Base ActiveRecord :: Base Page Controller Application Controller Page Wiki Create Page Runner <<protocol>> Repo Repo <<protocol>> context
  • 55. Enable Labs @mark_menard Action Controller :: Base ActiveRecord :: Base Page Controller Application Controller Page Wiki Create Page Runner <<protocol>> Repo Repo <<protocol>> context Domain
  • 56. Enable Labs @mark_menard Action Controller :: Base ActiveRecord :: Base Page Controller Application Controller Page Wiki Create Page Runner <<protocol>> Repo Repo <<protocol>> context Domain
  • 57. Enable Labs @mark_menard Action Controller :: Base ActiveRecord :: Base Page Controller Application Controller Page Wiki Create Page Runner <<protocol>> Repo Repo <<protocol>> context Domain
  • 58. Enable Labs @mark_menard # app/services/wiki_repository.rb class WikiRepository include Repo::UserMethods include Repo::WikiMethods include Repo::PageMethods include Repo::PermissionMethods end
  • 59. Enable Labs @mark_menard # app/services/repo/page_methods.rb module PageMethods def find_wiki_page(wiki_id, page_id) wiki = Wiki.find(wiki_id) page = wiki.pages.find(page_id) ! # … end ! # … ! def save_page(page) page.data.save end ! # … end
  • 62. Enable Labs @mark_menard Action Controller :: Base ActiveRecord :: Base Page Controller Application Controller Page Wiki Create Page Runner <<protocol>> Repo Repo <<protocol>> context Domain
  • 63. Enable Labs @mark_menard Biz Model ActiveRecord :: Base Simple Delegator
  • 64. Enable Labs @mark_menard # app/models/biz/model.rb module Biz class Model < SimpleDelegator include BlockActiveRecord ! def data datum = self while datum.biz? datum = datum.__getobj__ end datum end ! def ==(other) if other.respond_to?(:data) data == other.data else data == other end end def biz? true end ! def class data.class end ! def self.wrap(model) model ? new(model) : nil end ! def self.wraps(models) models.map { |model| wrap(model) } end ! end end
  • 65. Enable Labs @mark_menard # app/models/biz/model.rb module Biz class Model < SimpleDelegator include BlockActiveRecord ! def data datum = self while datum.biz? datum = datum.__getobj__ end datum end ! def ==(other) if other.respond_to?(:data) data == other.data else data == other end end def biz? true end ! def class data.class end ! def self.wrap(model) model ? new(model) : nil end ! def self.wraps(models) models.map { |model| wrap(model) } end ! end end
  • 66. Enable Labs @mark_menard # app/models/biz/model.rb module Biz class Model < SimpleDelegator include BlockActiveRecord ! def data datum = self while datum.biz? datum = datum.__getobj__ end datum end ! def ==(other) if other.respond_to?(:data) data == other.data else data == other end end def biz? true end ! def class data.class end ! def self.wrap(model) model ? new(model) : nil end ! def self.wraps(models) models.map { |model| wrap(model) } end ! end end
  • 67. Enable Labs @mark_menard # app/models/biz/model.rb module Biz class Model < SimpleDelegator include BlockActiveRecord ! def data datum = self while datum.biz? datum = datum.__getobj__ end datum end ! def ==(other) if other.respond_to?(:data) data == other.data else data == other end end def biz? true end ! def class data.class end ! def self.wrap(model) model ? new(model) : nil end ! def self.wraps(models) models.map { |model| wrap(model) } end ! end end
  • 68. Enable Labs @mark_menard # app/models/biz/model.rb module Biz class Model < SimpleDelegator include BlockActiveRecord ! def data datum = self while datum.biz? datum = datum.__getobj__ end datum end ! def ==(other) if other.respond_to?(:data) data == other.data else data == other end end def biz? true end ! def class data.class end ! def self.wrap(model) model ? new(model) : nil end ! def self.wraps(models) models.map { |model| wrap(model) } end ! end end
  • 69. Enable Labs @mark_menard # app/models/biz/model.rb module Biz class Model < SimpleDelegator include BlockActiveRecord ! def data datum = self while datum.biz? datum = datum.__getobj__ end datum end ! def ==(other) if other.respond_to?(:data) data == other.data else data == other end end def biz? true end ! def class data.class end ! def self.wrap(model) model ? new(model) : nil end ! def self.wraps(models) models.map { |model| wrap(model) } end ! end end
  • 70. Enable Labs @mark_menard # app/services/repo/page_methods.rb module PageMethods def find_wiki_page(wiki_id, page_id) wiki = Wiki.find(wiki_id) page = wiki.pages.find(page_id) Biz::Page.wrap(page) end ! # … ! def save_page(page) page.data.save end ! # … end
  • 71. Enable Labs @mark_menard # app/services/repo/page_methods.rb module PageMethods def find_wiki_page(wiki_id, page_id) wiki = Wiki.find(wiki_id) page = wiki.pages.find(page_id) Biz::Page.wrap(page) end ! # … ! def save_page(page) page.data.save end ! # … end
  • 72. Enable Labs @mark_menard module Biz class Page < Model def wiki Biz::Wiki.wrap(super) end ! def html_content(context) Kramdown::Document.new(referenced_content(context)).to_html end ! def referenced_content(context) content.gsub(/(([A-Z][a-z0-9]+){2,})/) { |page_name| if wiki.page?(context.repo, page_name) "[#{page_name}](#{context.named_page_path(wiki.name,page_name)})" elsif context.current_user.can_write?(wiki) "#{page_name}[?](#{context.new_named_page_path(wiki.name, page_name)})" else page_name end } end end end
  • 73. Enable Labs @mark_menard module Biz class Page < Model def wiki Biz::Wiki.wrap(super) end ! def html_content(context) Kramdown::Document.new(referenced_content(context)).to_html end ! def referenced_content(context) content.gsub(/(([A-Z][a-z0-9]+){2,})/) { |page_name| if wiki.page?(context.repo, page_name) "[#{page_name}](#{context.named_page_path(wiki.name,page_name)})" elsif context.current_user.can_write?(wiki) "#{page_name}[?](#{context.new_named_page_path(wiki.name, page_name)})" else page_name end } end end end
  • 74. Enable Labs @mark_menard Action Controller :: Base ActiveRecord :: Base Page Controller Application Controller Some Model Runner Repo Biz Model << wraps >>
  • 75. Enable Labs @mark_menard Action Controller :: Base ActiveRecord :: Base Page Controller Application Controller Some Model Runner Repo Biz Model << wraps >>
  • 81. Enable Labs @mark_menard $ time rspec spec/runners spec/models/biz (git)-[master] ...................................................................................................... ! Finished in 0.17573 seconds 102 examples, 0 failures rspec spec/runners spec/models/biz 0.61s user 0.07s system 99% cpu 0.683 total
  • 84. Enable Labs @mark_menard Start Today http://www.enablelabs.com/ mark@enablelabs.com 866-895-8189 Enable Labs @mark_menard