Notes posted by Mange
RSS feedWill raise error on broken symlink
This method will raise Errno::ENOENT on a broken symlink. You should probably rescue it every time you call this method.
Getting n..end in Rails
Nice one, henning. For anyone using Rails (ActiveSupport) a handy method called #from is also present.
[1, 2, 3, 4, 5].from(2) # => [3, 4, 5]
So our example would be
a.from(i)
It reads a lot better
Re: IE GOTCHA
@insane-dreamer
That has nothing to do with IE. When you specify :cache => true you are saying that the files referenced should be saved to a file called all.js. When the script encounters the next line, it will overwrite the same file with the new contents.
Caching is not compressing, it doesn’t make sense to do with individual files, but it can make sense some times. I someone wants to do it, just specify a name for the cached file:
javascript_include_tag 'layout', 'typography', :cache => 'base' javascript_include_tag 'admin/layout', 'admin/extras', :cache => 'admin'
RE: Replacing with "\" and match — a simple solution
Thanks. No, I am not trying to quote for a regex. It was mostly an approach thing since I came into contact with the behavior previously when I played around. After doing some tests, I figured I should spare any other adventurers that part. :-)
Setting primary key from hash
If you try to specify the value for your primary key (usually “id”) through the attributes hash, it will be stripped out:
Post.new(:id => 5, :title => 'Foo') #=> #<Post @id=nil @title="Foo">
You can solve this by setting it directly, perhaps by using a block:
Post.new(:title => "Foo") { |p| p.id = 5 } #=> #<Post @id=5 @title="Foo">
This behavior is something you’d probably only have a problem with when you have custom primary keys. Perhaps you have a User model with a primary key of “name”…
class User < ActiveRecord::Base set_primary_key :name end User.new(params[:user]) # This will never work
You can solve this on a case-to-case basis by calling attributes= directly with the “ignore protected” option:
User.new { |user| user.send(:attributes=, params[:user], false) } # BAD BAD BAD!
You should not do the above example, though. If you do, all protected attributes are ignored, which is very, very bad when you only care about the primary key.
I’d recommend one of the following instead:
# Option 1 – Always allow primary key. Avoid with models created by users class User private def attributes_protected_by_default super - [self.class.primary_key.to_s] end end # Option 2 – Add a new method for this case class User def self.new_with_name(attributes = nil) new(attributes) { |u| u.name = attributes[:name] } end end
As always when something is hard to do in Rails: Think about your design? Is it recommended? Is it sound? Do you really need to have a custom primary key?
:find takes more keys than written
The documentation says that the :find keywords “may include the :conditions, :joins, :include, :offset, :limit, and :readonly options”. Note that this does not mean that only those options are supported. :sort also works like it should, for example.
Replacing with "\" and match
If you’re trying to place a “" in front of your matches, you’ll quickly see that it is a pain in the ass to add the quoting in the replacement string.
Here’s an example:
v = "Foo Bar!" # Target: Foo\ Bar\! # Resulting strings will not be quoted to decrease # the amount of backslashes. Compare \\! to "\\\\!" v.gsub(/\W/, '\0') #=> Foo Bar! # \\ escapes to a literal \, which next to the 0 becomes \0 v.gsub(/\W/, '\\0') #=> Foo Bar! # \\\0, means "\ \0", or "escaped \0" v.gsub(/\W/, '\\\0') #=> Foo\0Bar\0 # Same mechanism as before. \\ → \ v.gsub(/\W/, '\\\\0') #=> Foo\0Bar\0 # Finally! We have now an escaped \ before \0 and # we get the results we want. v.gsub(/\W/, '\\\\\0') #=> Foo\ Bar\! # It's very tempting to just write it like this now, right? v.gsub(/\W/) { |m| "\\#{m}" } #=> Foo\ Bar\! # It might not be shorter, but anyone can understand it.
Surely, there must be an easier way to do this. I haven’t found it, though. Hopefully, this makes it easier for you to understand why it behaves the way it does. :-)
See Dir#glob
See glob for more usage information and comments.
Getting relative path from absolute globbing
Say you want to scan for files in directory base_dir and you want to use the relative path from this base dir, you could do it like this:
base_dir = '/path/to/dir' files = Dir[File.join(base_dir, '**', '*.yml')] # files now contain absolute paths: files.first # => "/path/to/dir/foo/bar.yml" # let's make them relative base_pathname = Pathname.new(base_dir) files = files.collect do |file| Pathname.new(file).relative_path_from(base_pathname) end files.first # => "foo/bar.yml"
Of course, a more common use-case could be the following:
def scan_for_documents! base_path = Pathname.new(self.base_path) self.contained_files = [] Dir[File.join(self.base_path, '**', '*.pdf')].each do |full_path| path = Pathname.new(full_path).relative_path_from(base_path) self.contained_files << path end end
Using argument version in ruby < 1.8.7
The argument to this method was added in Ruby 1.8.7. If you want to use this form in an earlier version, you must instead use the slice! method.
It is mentioned up in the docs, but here it is again for reference:
# Ruby >= 1.8.7 p = list.pop(n) # Ruby < 1.8.7 p = list.slice!(-n, n)
collect/map
If you’d like to use this method for something like Enumerable#collect, you are looking at the wrong place. This method will return the initial integer, not the values from the block.
a = 20.times { |n| n * 2 } #=> 20
Instead, use Range#collect:
a = (0...20).collect { n * 2 }
Getting (n..end)
It would seem like it would be possible to say, get everything from element i and to the end by saying
# WRONG! a[i, -1] # "From 2 to the last element"
but since the second parameter does not say the ending index, but instead the length, this is not possible and you will get nil from the above code.
What you should do instead is using that the length can be specified longer then how long it is going to be:
b = [1, 2, 3] # Return up to a million elements # (not "return an array WITH 1 million elements") b[2, 1_000_000] #=> [3] # Size is guaranteed to never be shorter # than our returned value should be a[i, a.size]
It is a waste to do something like this:
a[i, a.size - i] a[i..(a.size-i)]
This is an alias
Please comment under the real method instead: find_index
Using block version in Ruby < 1.8.7
The block usage was added in 1.8.7, so to get the same functionality in an earlier version of Ruby, you need to utilize the find method.
Here is a quick example:
match = list.find { |l| l.owner == myself } match_index = list.index(match)
If you do some gymnastics, you can have it on one line without extra variables:
match_index = list.index(list.find { |l| l.owner == myself })
Better autopad numbers
There is a much better way than to use diwadn’s method if you want to pad numbers with zeros. Here’s my recommended way to do it:
"Number: %010d" % 12345 #=> "Number: 0000012345"
It’s very easy. First we begin our placeholder with “%”, then we specify a zero (0) to signify padding with zeros. If we omitted this zero, the number would be padded with spaces instead. When we have done that, just specify the target length of the string. At last a single “d” is placed to signify that we are inserting a number.
Please see String#% and Kernel#sprintf for more information about how to do this.
Here’s another example of how to do it:
12345.to_s.rjust(10, "0") #=> "0000012345"
See String#rjust for more information.
Any of these methods are a lot better than the method outlined below.
Differences between normal or-assign operator
Differences between this method and normal memoization with ||=:
-
memoize works with false/nil values
-
Potential arguments are memoized
Take the following example:
def allowed? @allowed ||= begin # Big calculation puts "Worked" false end end allowed? # Outputs "Worked" allowed? # Outputs "Worked" again
Since @allowed is set to false (this is also applicable with nil), the ||= operator will move on the the next statement and will not be short-circuited.
When you use memoize you will not have this problem.
def allowed? # Big calculation puts "Worked" false end memoize :allowed? allowed? # Outputs "Worked" allowed? # No output
Now, look at the case where we have parameters:
def random(max=10) @random ||= rand(max) end random # => 4 random # => 4 -- Yay! random(20) # => 4 -- Oops!
Better use memoize again!
def random(max=10) rand(max) end memoize :random random # => 6 random # => 6 -- Yay! random(20) # => 12 -- Double-Yay! random # => 6 -- Head a'splode
Usage
This defines attr_accessors at a class level instead of instance level.
class Foo cattr_accessor :greeting end Foo.greeting = "Hello"
This could be compared to, but is not the same as doing this:
class Bar class << self attr_accessor :greeting end end Bar.greeting = "Hello"
The difference might not be apparent at first, but cattr_accessor will make the accessor inherited to the instances:
Foo.new.greeting #=> "Hello" Bar.new.greeting # NoMethodError: undefined method `greeting' for #<Bar:0x18e4d78>
This inheritance is also not copy-on-write in case you assumed that:
Foo.greeting #=> "Hello" foo1, foo2 = Foo.new, Foo.new foo1.greeting = "Hi!" Foo.greeting #=> "Hi!" foo2.greeting #=> "Hi!"
This makes it possible to share common state (queues, semaphores, etc.), configuration (max value, etc.) or temporary values through this.
Validate an optional URL field
Let’s say that you have an optional URL field to one of your models and you want to validate the URL. You can accomplish this by using the URI library:
require 'uri' # Put this at the beginning of your model file validates_each :url, :allow_blank => true do |record, field, value| begin valid = (URI.parse(value).scheme =~ /https?/) rescue URI::InvalidURIError valid = false end record.errors.add field, "not a valid url" unless valid end
If you want to add even more testing in there, just go ahead. For now, we just check that the link is to a HTTP resource, but you might have other requirements. This will allow stuff like “http://example” since “example” might be a valid intranet domain. If you want to check for a TLD in there, you can do so with a simple regexp.
For more information about the URI library, check out http://apidock.com/ruby/URI/
Empty elements
If you want to output an empty element (self-closed) like “br”, “img” or “input”, use the tag method instead.
Capping values
This method is very useful when you want to cap values:
# minimum ≤ value value = [input.to_i, minimum].max # value ≤ maximum value = [input.to_i, maximum].min # minimum ≤ value ≤ maximum value = [ [input.to_i, minimum].max, maximum ].min # Practical example: Make sure destination is within container destination.x = [ [current.x + current.velocity.x, 0].max, container.width ].min destination.y = [ [current.y + current.velocity.y, 0].max, container.height ].min
Usage example
Some examples:
# Remove even numbers (1..30).reject { |n| n % 2 == 0 } # => [1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29] # Remove years dividable with 4 (this is *not* the full leap years rule) (1950..2000).reject { |y| y % 4 != 0 } # => [1952, 1956, 1960, 1964, 1968, 1972, 1976, 1980, 1984, 1988, 1992, 1996, 2000] # Remove users with karma below arithmetic mean total = users.inject(0) { |total, user| total += user.karma } mean = total / users.size good_users = users.reject { |u| u.karma < mean }
Reverse of this
If you want to do the reverse of this, e.g. go from a specific date and back to a certain day of the previous week, you can implement it like this:
def last_week(day = :monday) days_into_week = { :monday => 0, :tuesday => 1, :wednesday => 2, :thursday => 3, :friday => 4, :saturday => 5, :sunday => 6} result = (self - 7).beginning_of_week + days_into_week[day] self.acts_like?(:time) ? result.change(:hour => 0) : result end
If you do not want to make your own method of this, but just want to do it in a regular chaining of date methods (like Date.today.next_year.at_midnight), you can do it like the following:
(date - 7).next_week(:tuesday) # Tuesday, last week
Please note that you just need to subtract 7 if you want to move back a week. Only use these methods if you want to go to a specific day of the week.
Reverse naming
The reverse of this is last_month and not previous_month, like one might believe from the naming.
Reverse naming
The reverse of this is last_year and not previous_year, like one might believe from the naming.
Calculating on an enumerable
Inject can easily be used to sum an enumerable or to get the product of it
[100, 200, 1000].inject(0) { |sum, value| sum += value } # => 1300 [100, 200, 1000].inject(1) { |sum, value| sum *= value } # => 20000000 # You can access members and move down in the data structures, too points.inject(0) { |sum, point| sum += point.y }
In the case of the first two examples, an easier way to do it in Ruby 1.9 is to use reduce:
[100, 200, 1000].reduce :+ # => 1300 [100, 200, 1000].reduce :* # => 20000000
Look at reduce for more examples on how to use this.
RE: Careful when building gems
I found out a way to combine using RDoc::usage when you are building a gem. By ripping out the code from the usage method you can create your own version which opens the correct file.
In my case, I skipped the file reading and just put the usage information in a string and used that directly.
Here is my code:
$usage = %Q{ = Synopsis ... = Usage ... == Options ... } # Shamefully stolen from RDoc#usage. We cannot use RDoc::usage because # RubyGems will call this from a wrapper, and #usage is hardcoded to look # at the top-level file instead of the current one. I have changed this # code to instead just parse a string. def usage_and_exit! markup = SM::SimpleMarkup.new flow_convertor = SM::ToFlow.new flow = markup.convert($usage, flow_convertor) options = RI::Options.instance formatter = options.formatter.new(options, "") formatter.display_flow(flow) exit(0) end
Look in usage_no_exit if you want to rip stuff out. It’s up to you how and if you implement this at all, but it’s a shortcut to use the RDoc code and formatting. Do also consider doing the formatting yourself by hand and just output that string instead.
Careful when building gems
If you are building a gem with executables and you think about using RDoc::Usage for facilitating the --help message, think again.
usage and usage_no_exit is hardcoded to look for the initial comment in the top level file being executed, which is normally fine, but when installing a gem, RubyGems will generate a wrapper executable for you, and usage will therefore look in that wrapper file for the comment instead of your own file.
The methods contain too much code to be easily monkey patched too. Hopefully, this will be fixed in a later version.
Getting functionality from instances
If you want to get this functionality from instances of the models too, you can easily monkey patch rails to allow this. This is only semi-bad practice, AFAIK.
In config/initializers/overrides.rb:
# # Wrapper for @model.human_attribute_name -> Model.human_attribute_name # class ActiveRecord::Base def human_attribute_name(*args) self.class.human_attribute_name(*args) end end
Now, why is this bad? Because we change a core class, and that makes maintainability a little bit harder since new developers will not know about this.
The good part is that is such a small thing and as long as human_attribute_name exists in the class, this extension will work.
Example usage:
# index.html.haml %th= User.human_attribute_name('login') %th= User.human_attribute_name('email') # ... # show.html.haml %p %strong= "#{@user.human_attribute_name('login')}: " = @user.login
In this example, about nothing was gained at all, really. A better example is when you are building helpers to do stuff like displaying model attributes for you and whatnot. Examples for this would be far too huge to show off here, but basically, you avoid having to do stuff like this:
if options.include? :model model = options[:model] model = model.class unless model.is_a? Class model.human_attribute_name(field) else # ... end
and you want to keep your views clean (@user vs. @user.class)