Last active
December 30, 2015 00:08
-
-
Save jnv/7746982 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"metadata": { | |
"name": "" | |
}, | |
"nbformat": 3, | |
"nbformat_minor": 0, | |
"worksheets": [ | |
{ | |
"cells": [ | |
{ | |
"cell_type": "heading", | |
"level": 1, | |
"metadata": {}, | |
"source": [ | |
"Refinements" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"slideshow": { | |
"slide_type": "slide" | |
} | |
}, | |
"source": [ | |
"> Due to Ruby\u2019s open classes you can redefine or add functionality to existing classes. This is called a **monkey patch**. Unfortunately the scope of such changes is global. All users of the monkey-patched class see the same changes. " | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"slideshow": { | |
"slide_type": "slide" | |
} | |
}, | |
"source": [ | |
"> Refinements are designed to reduce the impact of monkey patching on other users of the monkey-patched class. Refinements provide a way to extend a class locally." | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"slideshow": { | |
"slide_type": "slide" | |
} | |
}, | |
"source": [ | |
"```ruby\n", | |
"module TimeExtensions\n", | |
" refine Fixnum do\n", | |
" def minutes; self * 60; end\n", | |
" end\n", | |
"end\n", | |
"\n", | |
"class MyApp\n", | |
" using TimeExtensions\n", | |
"\n", | |
" def initialize\n", | |
" p 2.minutes\n", | |
" end\n", | |
"end\n", | |
"\n", | |
"MyApp.new # => 120\n", | |
"p 2.minutes # => NoMethodError\n", | |
"```" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"module JSONGenerator\n", | |
" refine String do\n", | |
" def to_json; inspect end\n", | |
" end\n", | |
" \n", | |
" refine Fixnum do\n", | |
" def to_json; to_s end\n", | |
" end\n", | |
" \n", | |
" refine Array do\n", | |
" def to_json\n", | |
" # Refinements can see one another, so we can use String#to_json and\n", | |
" # Fixnum#to_json as part of the definition of Array#to_json.\n", | |
" \"[\" + map { |x| x.to_json }.join(',') + \"]\"\n", | |
" end\n", | |
" end\n", | |
"end" | |
], | |
"language": "ruby", | |
"metadata": { | |
"slideshow": { | |
"slide_type": "slide" | |
} | |
}, | |
"outputs": [ | |
{ | |
"metadata": {}, | |
"output_type": "pyout", | |
"prompt_number": 15, | |
"text": [ | |
"#<refinement:Array@JSONGenerator>" | |
] | |
} | |
], | |
"prompt_number": 15 | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"using JSONGenerator\n", | |
"['lorem', 'ipsum', 3].to_json" | |
], | |
"language": "ruby", | |
"metadata": { | |
"slideshow": { | |
"slide_type": "slide" | |
} | |
}, | |
"outputs": [ | |
{ | |
"metadata": {}, | |
"output_type": "pyout", | |
"prompt_number": 14, | |
"text": [ | |
"\"[\\\"lorem\\\",\\\"ipsum\\\",3]\"" | |
] | |
} | |
], | |
"prompt_number": 14 | |
}, | |
{ | |
"cell_type": "heading", | |
"level": 3, | |
"metadata": { | |
"slideshow": { | |
"slide_type": "slide" | |
} | |
}, | |
"source": [ | |
"Subclasses & Reopening" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"```ruby\n", | |
"class ApplicationController\n", | |
" using JSONGenerator\n", | |
"end\n", | |
"\n", | |
"# Somewhere else:\n", | |
"class ApplicationController\n", | |
" p 123.to_json # Still works\n", | |
"end\n", | |
"\n", | |
"class UsersController < ApplicationController\n", | |
" p 123.to_json # Still works\n", | |
"end\n", | |
"```" | |
] | |
}, | |
{ | |
"cell_type": "heading", | |
"level": 2, | |
"metadata": { | |
"slideshow": { | |
"slide_type": "slide" | |
} | |
}, | |
"source": [ | |
"DCI: Data Context Interaction" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"```ruby\n", | |
"module Runner\n", | |
" refine User do\n", | |
" def run\n", | |
" puts \"I'm running!\"\n", | |
" end\n", | |
" end\n", | |
"end\n", | |
"\n", | |
"class UserRunsContext\n", | |
" using Runner\n", | |
"\n", | |
" def self.call\n", | |
" User.new.run \n", | |
" end\n", | |
"end\n", | |
"```" | |
] | |
}, | |
{ | |
"cell_type": "heading", | |
"level": 2, | |
"metadata": { | |
"slideshow": { | |
"slide_type": "slide" | |
} | |
}, | |
"source": [ | |
"Still not ready :(" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"module TimeExtensions\n", | |
" refine Fixnum do\n", | |
" def minutes; self * 60; end\n", | |
" end\n", | |
"end" | |
], | |
"language": "ruby", | |
"metadata": { | |
"slideshow": { | |
"slide_type": "fragment" | |
} | |
}, | |
"outputs": [ | |
{ | |
"output_type": "stream", | |
"stream": "stderr", | |
"text": [ | |
"<main>:1: warning: Refinements are experimental, and the behavior may change in future versions of Ruby!\n" | |
] | |
}, | |
{ | |
"metadata": {}, | |
"output_type": "pyout", | |
"prompt_number": 1, | |
"text": [ | |
"#<refinement:Fixnum@TimeExtensions>" | |
] | |
} | |
], | |
"prompt_number": 1 | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"class Hour\n", | |
" using TimeExtensions\n", | |
" def seconds\n", | |
" 60.minutes\n", | |
" end\n", | |
"end\n", | |
"Hour.new.seconds" | |
], | |
"language": "ruby", | |
"metadata": { | |
"slideshow": { | |
"slide_type": "fragment" | |
} | |
}, | |
"outputs": [ | |
{ | |
"ename": "NoMethodError", | |
"evalue": "undefined method `using' for Hour:Class", | |
"output_type": "pyerr", | |
"traceback": [ | |
"\u001b[31mNoMethodError\u001b[0m: undefined method `using' for Hour:Class", | |
"\u001b[37m<main>:1:in `<class:Hour>'\u001b[0m", | |
"\u001b[37m<main>:6:in `<main>'\u001b[0m", | |
"\u001b[37m/home/j/.rbenv/versions/2.0.0-p247/lib/ruby/gems/2.0.0/gems/iruby-0.1.7/lib/iruby/backend.rb:8:in `eval'\u001b[0m", | |
"\u001b[37m/home/j/.rbenv/versions/2.0.0-p247/lib/ruby/gems/2.0.0/gems/iruby-0.1.7/lib/iruby/backend.rb:8:in `eval'\u001b[0m", | |
"\u001b[37m/home/j/.rbenv/versions/2.0.0-p247/lib/ruby/gems/2.0.0/gems/iruby-0.1.7/lib/iruby/kernel.rb:105:in `execute_request'\u001b[0m", | |
"\u001b[37m/home/j/.rbenv/versions/2.0.0-p247/lib/ruby/gems/2.0.0/gems/iruby-0.1.7/lib/iruby/kernel.rb:57:in `run'\u001b[0m", | |
"\u001b[37m/home/j/.rbenv/versions/2.0.0-p247/lib/ruby/gems/2.0.0/gems/iruby-0.1.7/lib/iruby/command.rb:28:in `run_kernel'\u001b[0m", | |
"\u001b[37m/home/j/.rbenv/versions/2.0.0-p247/lib/ruby/gems/2.0.0/gems/iruby-0.1.7/lib/iruby/command.rb:15:in `run'\u001b[0m", | |
"\u001b[37m/home/j/.rbenv/versions/2.0.0-p247/lib/ruby/gems/2.0.0/gems/iruby-0.1.7/bin/iruby:6:in `<top (required)>'\u001b[0m", | |
"\u001b[37m/home/j/.rbenv/versions/2.0.0-p247/bin/iruby:23:in `load'\u001b[0m", | |
"\u001b[37m/home/j/.rbenv/versions/2.0.0-p247/bin/iruby:23:in `<main>'\u001b[0m" | |
] | |
} | |
], | |
"prompt_number": 3 | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"eval <<-EOF\n", | |
" using TimeExtensions\n", | |
" \n", | |
" class Hour\n", | |
" def seconds\n", | |
" 60.minutes\n", | |
" end\n", | |
" end\n", | |
" puts Hour.new.seconds\n", | |
"EOF" | |
], | |
"language": "ruby", | |
"metadata": { | |
"slideshow": { | |
"slide_type": "fragment" | |
} | |
}, | |
"outputs": [ | |
{ | |
"output_type": "stream", | |
"stream": "stdout", | |
"text": [ | |
"3600\n" | |
] | |
} | |
], | |
"prompt_number": 2 | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"http://bugs.ruby-lang.org/projects/ruby-200/repository/entry/test/ruby/test_refinement.rb" | |
], | |
"language": "ruby", | |
"metadata": { | |
"slideshow": { | |
"slide_type": "skip" | |
} | |
}, | |
"outputs": [] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"slideshow": { | |
"slide_type": "slide" | |
} | |
}, | |
"source": [ | |
"## Resources\n", | |
"\n", | |
"* http://timelessrepo.com/refinements-in-ruby\n", | |
"* http://www.ruby-doc.org/core-2.0.0/doc/syntax/refinements_rdoc.html\n", | |
"* http://mikepackdev.com/blog_posts/35-dci-with-ruby-refinements" | |
] | |
} | |
], | |
"metadata": {} | |
} | |
] | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment