Geplaatst door Michiel de Mare
ma, 11 feb 2008 07:20:00 GMT
Enumerable#inject is a terrific and flexible method – so flexible that I regularly abuse it:
Take for instance this fragment:
arr_of_arr.inject(Hash.new(0)) do |h,a|
a.each {|x| h[x] += 1 }
h
end
# I could simply use a local variable
h = Hash.new(0)
ar_of_ar.each do |h,a|
a.each {|x| h[x] += 1 }
end
# Ruby 1.9 offers Object#tap
Hash.new(0).tap do |h|
ar_of_ar.each do |a|
a.each {|x| h[x] += 1 }
end
end
And yet I like my inject
-solution better – no local variables or superfluous blocks. Why not change inject
by not returning the value of the block and using it in the next iteration, why not each time pass in the argument to inject
. Let’s name this function inject!
module Enumerable
def inject!(memo)
each {|x| yield(memo,x) }
memo
end
end
ar_of_ar.inject!(Hash.new(0)){|h,a| a.each{|x| h[x] += 1}}
Geplaatst in ruby, english, daily_method | geen reacties
Geplaatst door Remco van 't Veer
vr, 08 feb 2008 08:00:00 GMT
This will look familiar:
u = params[:user]
attr = if u[:password].blank?
u.reject do |k,_|
[:password, :password_confirmation].include?(k)
end
end
User.update_attributes(attr || u)
But it smells like something reusable. I would like to write:
u = params[:user]
attr = if u[:password].blank?
u.excluding(:password, :password_confirmation)
end
User.update_attributes(attr || u)
Easily to implement, including its little brother only
, with:
class Hash
def excluding(*keys)
reject{|k,_| keys.include?(k)}
end
def only(*keys)
reject{|k,_| !keys.include?(k)}
end
end
Disclaimer: the above example doesn’t really work in Rails because params
is a hash with indifferent access. Making an indifferent variant is up you! :)
Geplaatst in ruby, english, daily_method | 2 reacties
Geplaatst door Matthijs Langenberg
do, 07 feb 2008 10:02:00 GMT
At Newminds our internal test environment is running a Nginx webserver as a frontend proxying every request to a mongrel server. Recently, I wanted to setup page caching to increase the performance of our service. So, let me share my experience with you.
I’ll be describing what to put in the ‘server’ block of the nginx configuration. If you aren’t familiar with a nginx configuration file yet, you can checkout Ezra Zygmuntowicz’s Nginx example configuration.
Let’s start simple:
server {
location / {
proxy_pass http://mongrel
}
}
This will proxy all request to the mongrel server, which is fine but doesn’t serve any static content (cached) content of course. In order to do that, we will need to extend the above block a little bit.
server {
# specify document root
# see: http://wiki.codemongers.com/NginxHttpCoreModule#root
root /home/user/apps/my_app/current/public;
location / {
# if the file exists as a static file serve it directly
if (-f $request_filename) {
break;
}
# check for index.html for directory index
# if it's there on the filesystem then rewrite
# the url to add /index.html to the end of it
if (-f $request_filename/index.html) {
rewrite (.*) $1/index.html break;
}
# add .html to the end of the url and check the filesystem
# if it exists, serve it directly, else hit mongrel
if (-f $request_filename.html) {
rewrite (.*) $1.html break;
}
if (-f $request_filename) {
proxy_pass http://mongrel;
break;
}
}
Great! This will serve all our page cache as static content making the application blazing fast! But there is one flaw: a GET /fruits/23
will serve public/fruits/23.html
from the filesystem. That works as intended, but when someone wants to update this little fruit he will send a PUT /fruits/23
. When that happens, Nginx checks the filesystem on an existing file at public/fruits/23.html
, this check will return true and breaks. It will never hit mongrel. In fact Nginx even returns a 405 Method Not Allowed
HTTP status code, because Nginx only knows how to GET
a file, not how to PUT
one.
This means we need to modify the configuration so Nginx only serves the static content if the HTTP request method is GET
or HEAD
. This will lead us to the final configuration block, which passes all requests except GET
or HEAD
immediately to mongrel.
server {
# specify document root
# see: http://wiki.codemongers.com/NginxHttpCoreModule#root
root /home/user/apps/my_app/current/public;
location / {
# only try to serve a static file if the request method is GET or HEAD
# if it's anything else (POST for example) hit mongrel.
if ($request_method !~ "GET|HEAD") {
proxy_pass http://mongrel;
break;
}
# if the file exists as a static file serve it directly
if (-f $request_filename) {
break;
}
# check for index.html for directory index
# if it's there on the filesystem then rewrite
# the url to add /index.html to the end of it
if (-f $request_filename/index.html) {
rewrite (.*) $1/index.html break;
}
# add .html to the end of the url and check the filesystem
# if it exists, serve it directly, else hit mongrel
if (-f $request_filename.html) {
rewrite (.*) $1.html break;
}
if (-f $request_filename) {
proxy_pass http://mongrel;
break;
}
}
Let me know if this post was useful for you.
Geplaatst in english | Tags caching, nginx | 1 reactie
Geplaatst door Remco van 't Veer
do, 07 feb 2008 08:00:00 GMT
You have probably used it before; Hash.new
with a block to make a two-dimensional hash;
map = Hash.new{|h,k| h[k] = {}}
map[:dragon][:strength] = 9
But sometimes you need a multi-dimensional hash;
def Hash.multi
Hash.new{|h,k| h[k] = Hash.multi}
end
I use it in an application to construct a simple cache with complex keys;
CACHE = Hash.multi
def expensive_query(key)
cache = CACHE[:query][auth_level][current_channel]
unless cache.has_key?(key)
cache[key] = Server.query(auth_level, current_channel, key)
else
cache[key]
end
end
Geplaatst in ruby, english, daily_method | geen reacties
Geplaatst door Michiel de Mare
wo, 06 feb 2008 06:00:00 GMT
Most web-applications do not appear to have a lot to do with random numbers, online poker sites excepted (I hope), but they are surprisingly useful nevertheless. That’s why I’m introducing a new notation to express chance.
# this certainly works
redirect_to home_url if rand < 0.2222
# this is better
redirect_to home_url if rand(9) < 2
# but not as beautiful as this
redirect_to home_url if 2.in 9
# the code
class Numeric
def in(other)
rand(other) < self
end
end
Geplaatst in ruby, english, daily_method | geen reacties
Geplaatst door Michiel de Mare
di, 05 feb 2008 08:00:00 GMT
We’d like to introduce a new blog category: Our Daily Method. We’ll demonstrate short, general purpose methods, which might be suitable for the standard library. We’re accepting requests!
We’ll kick off with Range#coerce. The problem is: you’ve got a value and you wish to ensure that it’s within a certain interval. Sounds ideal for a Range, but it’s missing from Ruby’s Range, although there’s include?
(and in Ruby 1.9 cover?
) to test whether the value is in the range.
Hence the following:
class Range
def coerce(x)
x < first ? first : x > last ? last : x
end
end
(1..12).coerce(999)
Geplaatst in ruby, english, daily_method | geen reacties
Geplaatst door Michiel de Mare
ma, 08 okt 2007 22:03:24 GMT
We’ve decided to start an English section on this Dutch blog. We will translate some of our more technical articles. These articles will (we hope) not appear on the front page, but in the category “english”. A separate RSS-feed should be available soon.
Cheers,
The rubyenrails.nl team.
Geplaatst in blog, english | 1 reactie