Permalink
Browse files

removing codeblocks, thanks @sumeet_agarwal

  • Loading branch information...
1 parent 9429641 commit 7c5895f2b0ddbe43efd871075dbb3c6b09a68ad9 @steveklabnik committed Dec 30, 2011
@@ -31,7 +31,7 @@ it hides in plain sight. Loved by those who've mastered Rails, Plain Old Ruby
Objects, or "POROs" as some like to call them, are a hidden weapon against
complexity. Here's what I mean. Examine this 'simple' model:
-{% codeblock lang:ruby %}
+``` ruby
class Post < ActiveRecord::Base
def self.as_dictionary
dictionary = ('A'..'Z').inject({}) {|h, l| h[l] = []; h}
@@ -43,26 +43,26 @@ class Post < ActiveRecord::Base
dictionary
end
end
-{% endcodeblock %}
+```
We want to display an index page of all our posts, and do it by first letter.
So we build up a dictionary, and then put our posts in it. I'm assuming we're
not paginating this, so don't get caught up in querying for all Posts. The
important thing is the idea: we can now display our posts by title:
-{% codeblock lang:haml %}
+``` ruby
- Post.as_dictionary do |letter, list|
%p= letter
%ul
- list.each do |post|
%li= link_to post
-{% endcodeblock %}
+```
Sure. And in one way, this code isn't _bad_. It's also not good: We've mixed a
presentational concern into our model, which is supposed to represent buisness
logic. So let's fix that, via a Presenter:
-{% codeblock lang:ruby %}
+``` ruby
class DictionaryPresenter
def initialize(collection)
@collection = collection
@@ -78,7 +78,7 @@ class DictionaryPresenter
dictionary
end
end
-{% endcodeblock %}
+```
We can use it via `DictionaryPresenter.new(Post.all).as_dictionary`. This has
tons of benefits: we've moved presentation logic out of the model. We've
@@ -100,7 +100,7 @@ again. You guessed it: POROs to the rescue!
Let's change our presenter slightly, to also accept an organizational policy
object:
-{% codeblock lang:ruby %}
+``` ruby
class DictionaryPresenter
def initialize(policy, collection)
@policy = policy
@@ -117,11 +117,11 @@ class DictionaryPresenter
dictionary
end
end
-{% endcodeblock %}
+```
Now, we can inject a policy, and have them be different:
-{% codeblock lang:ruby %}
+``` ruby
class UserCategorizationPolicy
def self.category_for(user)
user.username[0]
@@ -137,13 +137,13 @@ class PostCategorizationPolicy
end
end
end
-{% endcodeblock %}
+```
Bam!
-{% codeblock lang:ruby %}
+``` ruby
DictionaryPresenter.new(PostCategorizationPolicy, Post.all).as_dictionary
-{% endcodeblock %}
+```
Yeah, so that's getting a bit long. It happens. :) You can see that now each
concept has one representation in our system. The presenter doesn't care how
@@ -156,7 +156,7 @@ Ruby with one of my favorite patterns from "Working Effectively with Legacy
Code," we can take complex computations and turn them into objects. Look at this
code:
-{% codeblock lang:ruby %}
+``` ruby
class Quote < ActiveRecord::Base
#<snip>
def pretty_turnaround
@@ -178,7 +178,7 @@ class Quote < ActiveRecord::Base
"#{time.strftime("%A %d %B")} (#{days_from_today} business days from today)"
end
end
-{% endcodeblock %}
+```
Yikes! This method prints a turnaround time, but as you can see, it's a complex
calculation. We'd be able to understand this much more easily of we used Extract
@@ -202,7 +202,7 @@ I've changed this slightly for Ruby, since we can't Lean On The Compiler, and a
few of Feathers' steps are about doing this. Anyway, let's try this on that
code. Step 1:
-{% codeblock lang:ruby %}
+``` ruby
class Quote < ActiveRecord::Base
def pretty_turnaround
#snip
@@ -211,20 +211,20 @@ class Quote < ActiveRecord::Base
class TurnaroundCalculator
end
end
-{% endcodeblock %}
+```
Two:
-{% codeblock lang:ruby %}
+``` ruby
class TurnaroundCalculator
def calculate
end
end
-{% endcodeblock %}
+```
Three:
-{% codeblock lang:ruby %}
+``` ruby
class TurnaroundCalculator
def calculate
return "" if @turnaround.nil?
@@ -245,15 +245,15 @@ class TurnaroundCalculator
"#{time.strftime("%A %d %B")} (#{days_from_today} business days from today)"
end
end
-{% endcodeblock %}
+```
I like to give it a generic name at first, and then give it a better one in step
5, after we see what it really does. often our code will inform us of a good
name.
Four:
-{% codeblock lang:ruby %}
+``` ruby
class TurnaroundCalculator
def initialize(purchased_at, turnaround)
@purchased_at = purchased_at
@@ -264,17 +264,17 @@ class TurnaroundCalculator
#snip
end
end
-{% endcodeblock %}
+```
Five:
-{% codeblock lang:ruby %}
+``` ruby
class Quote < ActiveRecord::Base
def pretty_turnaround
TurnaroundCalculator.new(purchased_at, turnaround).calculate
end
end
-{% endcodeblock %}
+```
Done! We should be able to run our tests and see them pass. Even if 'run our
tests' consists of manually checking it out...
@@ -286,7 +286,7 @@ for just the Calculator, and we've split out the idea of calculation into one
place, where it can easily be changed later. Here's our class, a few
refactorings later:
-{% codeblock lang:ruby %}
+``` ruby
class TurnaroundCalculator
def calculate
return "" if @turnaround.nil?
@@ -338,7 +338,7 @@ class TurnaroundCalculator
end
end
end
-{% endcodeblock %}
+```
Wow. This code I wrote three years ago isn't perfect, but it's almost
understandable now. And each of the bits makes sense. This is after two or three
@@ -350,24 +350,24 @@ is well-factored, you can often get there.
This idea of extracting domain objects that are pure Ruby is even in Rails
itself. Check out this route:
-{% codeblock lang:ruby %}
+``` ruby
root :to => 'dashboard#index', :constraints => LoggedInConstraint
-{% endcodeblock %}
+```
Huh? LoggedInConstraint?
-{% codeblock lang:ruby %}
+``` ruby
class LoggedInConstraint
def self.matches?(request)
current_user
end
end
-{% endcodeblock %}
+```
Whoah. Yep. A domain object that describes our routing policy. Awesome. Also,
validations, blatantly stolen from [omgbloglol](http://omgbloglol.com/post/392895742/improved-validations-in-rails-3):
-{% codeblock lang:ruby %}
+``` ruby
def SomeClass < ActiveRecord::Base
validate :category_id, :proper_category => true
end
@@ -379,7 +379,7 @@ class ProperCategoryValidator < ActiveModel::EachValidator
end
end
end
-{% endcodeblock %}
+```
This isn't a plain Ruby class, but you get the idea.
@@ -38,7 +38,7 @@ post, so just keep that in the back of your brain.
Well, first of all, [class methods also suck](http://nicksda.apotomo.de/2011/07/are-class-methods-evil/). Here's the
issue: Can you tell me the difference between these two methods?
-{% codeblock lang:ruby %}
+``` ruby
def foo
"hello"
end
@@ -51,7 +51,7 @@ end
foo
Bar.foo
-{% endcodeblock %}
+```
Yep, that's right. You can see it clearly from the last two lines: class methods
are functions that happen to be namespaced. That means they're slightly better,
@@ -64,7 +64,7 @@ world example, but...) generally works a little different. Usually, I make
presenters that actually stand in for the objects they're presenting. Check
this out. Here's the presenter I showed you:
-{% codeblock lang:ruby %}
+``` ruby
class DictionaryPresenter
def initialize(collection)
@collection = collection
@@ -80,11 +80,11 @@ class DictionaryPresenter
dictionary
end
end
-{% endcodeblock %}
+```
The real-world presenter that I used this for looked like this:
-{% codeblock lang:ruby %}
+``` ruby
class DictionaryPresenter
include Enumerable
@@ -100,20 +100,20 @@ class DictionaryPresenter
@dictionary.each &blk
end
end
-{% endcodeblock %}
+```
... or close to this. There was an 'other' category, and a few other things...
but you get the idea. Now, instead of this:
-{% codeblock lang:ruby %}
+``` ruby
@posts = DictionaryPresenter.new(Post.all).as_dictionary
-{% endcodeblock %}
+```
You do this:
-{% codeblock lang:ruby %}
+``` ruby
@posts = DictionaryPresenter.new(Post.all)
-{% endcodeblock %}
+```
And the presenter actually stands in for the hash. A subtle but important
difference. This gives you more options, because you have a real, live object
@@ -136,7 +136,7 @@ blocks.
For reference, the old code, put into the new code:
-{% codeblock lang:ruby %}
+``` ruby
class DictionaryPresenter
include Enumerable
@@ -158,11 +158,11 @@ class UserCategorizationPolicy
user.username[0]
end
end
-{% endcodeblock %}
+```
We could use blocks instead:
-{% codeblock lang:ruby %}
+``` ruby
class DictionaryPresenter
include Enumerable
@@ -182,7 +182,7 @@ end
DictionaryPresenter.new(Post.all) do |item|
item.title[0]
end
-{% endcodeblock %}
+```
While this is shorter, and a bit more Rubyish, it also means that we lose the
<a href="http://en.wikipedia.org/wiki/Reification_(computer_science)">reification</a> of
@@ -195,7 +195,7 @@ This does get to the root of another thing that will end up being a follow-up:
What's the difference between closures and objects? If you don't know, maybe
this will get you thinking:
-{% codeblock lang:ruby %}
+``` ruby
#ugh, this is slightly odd, thanks Ruby!
def apply(proc=nil, &blk)
if block_given?
@@ -224,7 +224,7 @@ end
apply proc
apply my_proc
-{% endcodeblock %}
+```
Chew on that a while.
@@ -233,9 +233,9 @@ Chew on that a while.
Absolutely. `DictionaryPresenter.new(PostCategorizationPolicy, Post.all).as_dictionary`
is too long. 100% there. Good thing that I'd _actually_ write this:
-{% codeblock lang:ruby %}
+``` ruby
Dictionary.new(Post.all, ByTitle)
-{% endcodeblock %}
+```
I switched the arguments around, because it reads better. When writing blog
posts, you have to balance writing code samples that explain what you're
@@ -287,7 +287,7 @@ Ruby classes, but if they get slightly more complicated, you need to check out
[Draper](https://github.com/jcasimir/draper) by my buddy Jeff Casimir. It lets
you do stuff like this:
-{% codeblock lang:ruby %}
+``` ruby
class ArticleDecorator < ApplicationDecorator
decorates :article
@@ -298,6 +298,6 @@ end
article = ArticleDecorator.find(1)
article.author_name
-{% endcodeblock %}
+```
There's a lot of features to it, so check it out on GitHub. Totally worthwhile.
@@ -18,7 +18,7 @@ against modules. The answer was, 'because it's simpler, and the first thing
I thought of.' He shared with me an alternate implementation that I like too,
and I wanted to share with you. Check it:
-```ruby app/models/salmon_notifier.rb
+``` ruby app/models/salmon_notifier.rb
class SalmonNotifier
def initialize(user, feed)
@user = user

0 comments on commit 7c5895f

Please sign in to comment.