I just released rails_best_practices 1.1.0, the changes are as follows:
1. add "restrict auto-generated routes" check, http://rails-bestpractices.com/posts/86-restrict-auto-generated-routes
2. remove forced haml dependency (thanks @square)
3. add controller_prepare to remember all controllers' methods
4. use official progressbar gem instead of ruby-progressbar
Check it here, https://github.com/flyerhzm/rails_best_practices
I was finding a cache implementation a few days ago, I prefer cache-money gem, it provides a transparent cache way, really great. But it doesn't support rails3, ngmoco repository has a rails3 branch, but it doesn't work yet.
So I decided to write a simple cache system by myself. Here are the apis that I expected
1. cache by id
User.find(1) => User.find_cached(1)
2. cache by attribute
User.find_by_email("firstname.lastname@example.org") => User.find_cached_by_email("email@example.com")
3. cache by method
user.popular_tags => user.cached_popular_tags
4. cache by association (belongs_to, has_one and has_many)
post.user => post.cached_user
And the cached object will be expired after the object is updated.
I just released the gem simple_cacheable, https://github.com/flyerhzm/simple_cacheable, it provides a DSL to add cache ability to your models, it's easy to use, here is an example
class Post < ActiveRecord::Base include Cacheable belongs_to :user has_many :comments model_cache do with_key # Post.find_cached(1) with_attribute :title # Post.find_cached_by_title("title") with_association :user # post.cached_user with_method :last_comment # post.cached_last_comment end def last_comment comments.last end end
first, you should include Cacheable module provided by simple_cacheable, then define the cache by model_cache, there are 4 caches methods
1. with_key, cache for find(id)
2. with_attribute, cache for find_by_xxx
3. with_method, cache for a model method
4. with_association, cache for association (belongs_to, has_one and has_many)
I already used it in developing the website, works well now.
I just released rails_best_practices 1.0.0, the changes are as follows:
1. The parser is rewritten, I use ripper instead of ruby_parser, it supports ruby 1.9 perfectly now.
2. Use ripper18 gem to make it work in ruby 1.8 as well.
Check it here https://github.com/flyerhzm/rails_best_practices
Updated: I also released 1.0.1 to fix the line output error for constant node.
I have used ripper instead of ruby_parser from rails_best_practices version 1.0.0
I gave a presentation about rails_best_practices gem in RubyKaigi 2011 Tokyo this July.
One of the attendees asked me a question,
You implement the rails_best_practices based on ruby_parser, but ruby_parser can't support ruby 1.9 well, e.g. json hash, do you have plan to solve this?
My answer is,
Yes, there are two options, one is to change the source codes of ruby_parser, make it support the new ruby 1.9 syntax, the other is to use ripper, which is one of the new libraries in ruby 1.9, it supports all the ruby 1.9 new syntax, but doesn't support ruby 1.8.
After that, I don't have enough time to take care of that, but more and more developer open tickets on github to ask for support ruby 1.9 json hash, so I spent these two weekends to rewrite the rails_best_practices gem, replacing the ruby_parser with ripper. The following is my experience to use ripper to parse your ruby codes.
Difference between ruby_parser and ripper
So what's the biggest difference between ruby_parser and ripper?
ruby_parser provides the DOM-style way to parse the ruby source codes to S-expression, wrapped by sexp_processor.
ripper provides both the DOM-style and SAX-style to parse the ruby source codes, but the parsing result is just multidimensional arrays, not wrapped by sexp_processor.
Another big difference is that the parsing results of ruby_parser and ripper are totally different.
The result of ruby_parser contains scope, but ripper doesn't have.
The sexp type of their results are different, and not one to one correspondence.
user.logn = "richard" as a method call, but ripper treats it as an assign.
user == current_user as a method call, but ripper treats it as an binary operation.
ruby_parser will put multiple arguments or statements in the same dimension in the array, but ripper will put them in the multiple dimensions.
There are a lot of other differences that you will encounter when you change the parser from ruby_parser to ripper.
What I use in rails_best_practices
So what I use now? it's DOM-style ripper. Why?
I decided to use ripper instead of ruby_parser, because ripper is the standard library in ruby 1.9, that means it can support all the new syntax introduced by ruby 1.9. In future, I think it will work in 1.9.3, and even in ruby 2.0.
Then I make some experiments to check if I should use SAX-style or DOM-style ripper.
I tried SAX-style ripper first, extend Ripper::SexpBuilder class, register the events that I interested in, it works but not for my case. e.g. if the source codes are
class User def name "richard" end end
the SAX-style tells you the parsing result from bottom to top, first is string "richard", then method define name, and finally the class User, which is the opposite to what I expected.
So I choose DOM-style ripper, it provides the top to bottom result just like ruby_parser. To visit the result easier, I use sexp_processor to wrap.
Now result of the above code is the S-expression for the provided source code, one thing should notice that ruby_parser will set the filename and line number to every sexp node, but the result of above code doesn't contain.
If you use SAX-style, ripper provide the accessor to filename and lineno for you, but in DOM-style, you have to take care of the filename by yourself, luckily the result of DOM-style ripper contains line number and column number for some nodes, like
[:const_ref, [:@const, "User", [1, 8]]], 1 is the line number and 8 is the column number.
Here I want to thank @lsegal, who writes ripper18 gem, which makes ripper to be avaiable to ruby 1.8, check it here: https://github.com/lsegal/ripper18
You can get more usages of ripper in rails_best_practices source codes, https://github.com/flyerhzm/rails_best_practices
I just released rails_best_practices 0.10.0, thank raydog153's contributes, the changes are as follows:
1. add "remove tab" check, http://rails-bestpractices.com/posts/81-remove-tab
2. fix sorting in infinute loop
Check it here, https://github.com/flyerhzm/rails_best_practices