SlideShare uma empresa Scribd logo
1 de 84
Baixar para ler offline
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

Mais conteúdo relacionado

Mais procurados

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 AngularJSShekhar Gulati
 
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 RailsDave Bouwman
 
Enemy of the state
Enemy of the stateEnemy of the state
Enemy of the stateMike North
 
Poisoning Google images
Poisoning Google imagesPoisoning Google images
Poisoning Google imageslukash4
 
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 appAndrew Skiba
 
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 - #wcmiaRoy Sivan
 
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
 
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 | #wcmiaRoy Sivan
 
Story Driven Development With Cucumber
Story Driven Development With CucumberStory Driven Development With Cucumber
Story Driven Development With CucumberSean Cribbs
 
Merb Slices
Merb SlicesMerb Slices
Merb Sliceshassox
 
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 2015Matt Raible
 
CPAN Dependency Heaven
CPAN Dependency HeavenCPAN Dependency Heaven
CPAN Dependency HeavenOpusVL
 
Code diving in Ruby and Rails
Code diving in Ruby and RailsCode diving in Ruby and Rails
Code diving in Ruby and Railslrdesign
 
Hosting Your Own OTA Update Service
Hosting Your Own OTA Update ServiceHosting Your Own OTA Update Service
Hosting Your Own OTA Update ServiceQuinlan Jung
 
Nightwatch at Tilt
Nightwatch at TiltNightwatch at Tilt
Nightwatch at TiltDave King
 
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.9Ilya Grigorik
 
20160905 - BrisJS - nightwatch testing
20160905 - BrisJS - nightwatch testing20160905 - BrisJS - nightwatch testing
20160905 - BrisJS - nightwatch testingVladimir Roudakov
 
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 2015Roy Sivan
 

Mais procurados (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
 

Destaque

Small Code - Ruby on Ales 2014
Small Code - Ruby on Ales 2014Small Code - Ruby on Ales 2014
Small Code - Ruby on Ales 2014Mark Menard
 
Write Small Things (Code)
Write Small Things (Code)Write Small Things (Code)
Write Small Things (Code)Mark Menard
 
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 2014Mark Menard
 
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 2013Mark Menard
 
Small Code - RailsConf 2014
Small Code - RailsConf 2014Small Code - RailsConf 2014
Small Code - RailsConf 2014Mark Menard
 
JRuby 6 Years in Production
JRuby 6 Years in ProductionJRuby 6 Years in Production
JRuby 6 Years in ProductionMark Menard
 
Startup Lessons Learned
Startup Lessons LearnedStartup Lessons Learned
Startup Lessons LearnedMark Menard
 

Destaque (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
 

Semelhante a A Tour of Wyriki

Pourquoi ruby et rails déchirent
Pourquoi ruby et rails déchirentPourquoi ruby et rails déchirent
Pourquoi ruby et rails déchirentNicolas Ledez
 
Rails Engine | Modular application
Rails Engine | Modular applicationRails Engine | Modular application
Rails Engine | Modular applicationmirrec
 
浜松Rails3道場 其の四 View編
浜松Rails3道場 其の四 View編浜松Rails3道場 其の四 View編
浜松Rails3道場 其の四 View編Masakuni Kato
 
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 developergicappa
 
Building web framework with Rack
Building web framework with RackBuilding web framework with Rack
Building web framework with Racksickill
 
Ruby on Rails - Introduction
Ruby on Rails - IntroductionRuby on Rails - Introduction
Ruby on Rails - IntroductionVagmi Mudumbai
 
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 frameworkPankaj Bhageria
 
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 CloudHiro Asari
 
Tdc 2013 - Ecossistema Ruby
Tdc 2013 - Ecossistema RubyTdc 2013 - Ecossistema Ruby
Tdc 2013 - Ecossistema RubyFabio Akita
 
Rails 3: Dashing to the Finish
Rails 3: Dashing to the FinishRails 3: Dashing to the Finish
Rails 3: Dashing to the FinishYehuda Katz
 
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 '11Pedro Cunha
 
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 AppsMike Subelsky
 
Rails 3 overview
Rails 3 overviewRails 3 overview
Rails 3 overviewYehuda Katz
 
An introduction-to-ruby-on-rails
An introduction-to-ruby-on-railsAn introduction-to-ruby-on-rails
An introduction-to-ruby-on-railsvinicorp
 
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 20100506Vu 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 2011Nick Sieger
 
Spring into rails
Spring into railsSpring into rails
Spring into railsHiro Asari
 
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 JasminePaulo Ragonha
 

Semelhante a 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
 

Mais de Mark Menard

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

Mais 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
 

Último

From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .Alan Dix
 
Take control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test SuiteTake control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test SuiteDianaGray10
 
Scale your database traffic with Read & Write split using MySQL Router
Scale your database traffic with Read & Write split using MySQL RouterScale your database traffic with Read & Write split using MySQL Router
Scale your database traffic with Read & Write split using MySQL RouterMydbops
 
Sample pptx for embedding into website for demo
Sample pptx for embedding into website for demoSample pptx for embedding into website for demo
Sample pptx for embedding into website for demoHarshalMandlekar2
 
How to Effectively Monitor SD-WAN and SASE Environments with ThousandEyes
How to Effectively Monitor SD-WAN and SASE Environments with ThousandEyesHow to Effectively Monitor SD-WAN and SASE Environments with ThousandEyes
How to Effectively Monitor SD-WAN and SASE Environments with ThousandEyesThousandEyes
 
Generative AI for Technical Writer or Information Developers
Generative AI for Technical Writer or Information DevelopersGenerative AI for Technical Writer or Information Developers
Generative AI for Technical Writer or Information DevelopersRaghuram Pandurangan
 
Digital Identity is Under Attack: FIDO Paris Seminar.pptx
Digital Identity is Under Attack: FIDO Paris Seminar.pptxDigital Identity is Under Attack: FIDO Paris Seminar.pptx
Digital Identity is Under Attack: FIDO Paris Seminar.pptxLoriGlavin3
 
Emixa Mendix Meetup 11 April 2024 about Mendix Native development
Emixa Mendix Meetup 11 April 2024 about Mendix Native developmentEmixa Mendix Meetup 11 April 2024 about Mendix Native development
Emixa Mendix Meetup 11 April 2024 about Mendix Native developmentPim van der Noll
 
How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.Curtis Poe
 
Manual 508 Accessibility Compliance Audit
Manual 508 Accessibility Compliance AuditManual 508 Accessibility Compliance Audit
Manual 508 Accessibility Compliance AuditSkynet Technologies
 
Time Series Foundation Models - current state and future directions
Time Series Foundation Models - current state and future directionsTime Series Foundation Models - current state and future directions
Time Series Foundation Models - current state and future directionsNathaniel Shimoni
 
A Deep Dive on Passkeys: FIDO Paris Seminar.pptx
A Deep Dive on Passkeys: FIDO Paris Seminar.pptxA Deep Dive on Passkeys: FIDO Paris Seminar.pptx
A Deep Dive on Passkeys: FIDO Paris Seminar.pptxLoriGlavin3
 
Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...
Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...
Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...Alkin Tezuysal
 
The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...
The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...
The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...Wes McKinney
 
Rise of the Machines: Known As Drones...
Rise of the Machines: Known As Drones...Rise of the Machines: Known As Drones...
Rise of the Machines: Known As Drones...Rick Flair
 
TrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data PrivacyTrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data PrivacyTrustArc
 
DevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsDevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsSergiu Bodiu
 
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptxThe Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptxLoriGlavin3
 
Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24
Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24
Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24Mark Goldstein
 
Moving Beyond Passwords: FIDO Paris Seminar.pdf
Moving Beyond Passwords: FIDO Paris Seminar.pdfMoving Beyond Passwords: FIDO Paris Seminar.pdf
Moving Beyond Passwords: FIDO Paris Seminar.pdfLoriGlavin3
 

Último (20)

From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .
 
Take control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test SuiteTake control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test Suite
 
Scale your database traffic with Read & Write split using MySQL Router
Scale your database traffic with Read & Write split using MySQL RouterScale your database traffic with Read & Write split using MySQL Router
Scale your database traffic with Read & Write split using MySQL Router
 
Sample pptx for embedding into website for demo
Sample pptx for embedding into website for demoSample pptx for embedding into website for demo
Sample pptx for embedding into website for demo
 
How to Effectively Monitor SD-WAN and SASE Environments with ThousandEyes
How to Effectively Monitor SD-WAN and SASE Environments with ThousandEyesHow to Effectively Monitor SD-WAN and SASE Environments with ThousandEyes
How to Effectively Monitor SD-WAN and SASE Environments with ThousandEyes
 
Generative AI for Technical Writer or Information Developers
Generative AI for Technical Writer or Information DevelopersGenerative AI for Technical Writer or Information Developers
Generative AI for Technical Writer or Information Developers
 
Digital Identity is Under Attack: FIDO Paris Seminar.pptx
Digital Identity is Under Attack: FIDO Paris Seminar.pptxDigital Identity is Under Attack: FIDO Paris Seminar.pptx
Digital Identity is Under Attack: FIDO Paris Seminar.pptx
 
Emixa Mendix Meetup 11 April 2024 about Mendix Native development
Emixa Mendix Meetup 11 April 2024 about Mendix Native developmentEmixa Mendix Meetup 11 April 2024 about Mendix Native development
Emixa Mendix Meetup 11 April 2024 about Mendix Native development
 
How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.
 
Manual 508 Accessibility Compliance Audit
Manual 508 Accessibility Compliance AuditManual 508 Accessibility Compliance Audit
Manual 508 Accessibility Compliance Audit
 
Time Series Foundation Models - current state and future directions
Time Series Foundation Models - current state and future directionsTime Series Foundation Models - current state and future directions
Time Series Foundation Models - current state and future directions
 
A Deep Dive on Passkeys: FIDO Paris Seminar.pptx
A Deep Dive on Passkeys: FIDO Paris Seminar.pptxA Deep Dive on Passkeys: FIDO Paris Seminar.pptx
A Deep Dive on Passkeys: FIDO Paris Seminar.pptx
 
Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...
Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...
Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...
 
The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...
The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...
The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...
 
Rise of the Machines: Known As Drones...
Rise of the Machines: Known As Drones...Rise of the Machines: Known As Drones...
Rise of the Machines: Known As Drones...
 
TrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data PrivacyTrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data Privacy
 
DevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsDevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platforms
 
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptxThe Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
 
Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24
Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24
Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24
 
Moving Beyond Passwords: FIDO Paris Seminar.pdf
Moving Beyond Passwords: FIDO Paris Seminar.pdfMoving Beyond Passwords: FIDO Paris Seminar.pdf
Moving Beyond Passwords: FIDO Paris Seminar.pdf
 

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