poniedziałek, 30 sierpnia 2010

Dynamically removing some website content in Rails 3 Way (Prototype, UJS)


<div id="search">
  <div class="results">
    Search results
  </div>
  <%= link_to 'Reset results', '#', :'data-remove' => '#search .results' %>
</div>



document.observe("dom:loaded", function() {
$(document.body).observe("click", function(event) {
element = event.findElement();
resetWhat = element.readAttribute('data-remove')
if(resetWhat) {
resetable = $$(resetWhat);
for(var i=0; i< resetable.size(); i++) {
resetable[i].remove();
}
event.stop();
return false;
}
return true;
});
});



You could implement data-show, data-hide, data-toggle, data-appear etc. in the same easy way :-) I can certainly imagine hundreds of applications for such data-* custom attributes. Hopefully, we will have some libraries which will make good use of this pattern.



You can check it live here: Live heroku application with demos

Visit rails3-demos github repository to see the source code and colaborate on other demos. Be creative!

środa, 18 sierpnia 2010

Module#attr_accessor_with_default by Rails3 (and its speed measured by benchmark)

Did you know that every time you change the value it will recreate reader method?

class Module
# Declare an attribute accessor with an initial default return value.
#
# To give attribute :age the initial value 25:
#
# class Person
# attr_accessor_with_default :age, 25
# end
#
# some_person.age
# => 25
# some_person.age = 26
# some_person.age
# => 26
#
# To give attribute :element_name a dynamic default value, evaluated
# in scope of self:
#
# attr_accessor_with_default(:element_name) { name.underscore }
#
def attr_accessor_with_default(sym, default = nil, &block)
raise 'Default value or block required' unless !default.nil? || block
define_method(sym, block_given? ? block : Proc.new { default })
module_eval(<<-EVAL, __FILE__, __LINE__ + 1)
def #{sym}=(value) # def age=(value)
class << self; attr_reader :#{sym} end # class << self; attr_reader :age end
@#{sym} = value # @age = value
end # end
EVAL
end
end



The effect is like that:


BigNumber = 1_000_000

def test
BigNumber.times do
yield
end
end

Benchmark.bmbm do |x|

x.report("normal") do
klass = Class.new
klass.class_eval {attr_accessor :age}
k = klass.new
test do
k.age = 12
end
end

x.report("default") do
klass = Class.new
klass.class_eval { attr_accessor_with_default :age, 25 }
k = klass.new
test do
k.age = 12
end
end
end


Rehearsal -------------------------------------------
normal 0.230000 0.000000 0.230000 ( 0.230735)
default 5.500000 0.000000 5.500000 ( 5.503365)
---------------------------------- total: 5.730000sec

user system total real
normal 0.220000 0.000000 0.220000 ( 0.220314)
default 5.440000 0.000000 5.440000 ( 5.439583)

String#constantize . Can it be faster ?


BigNumber = 100_000
Constants = ["Rails", "ActiveSupport::Autoload", "ActiveSupport::Dependencies::LoadingModule"]

def test
BigNumber.times do
Constants.each do |c|
yield c
end
end
end

Benchmark.bmbm do |x|

x.report("custom ok") do
test do |const|
const = '::' << const unless const.starts_with?("::")
eval(const)
end
end

x.report("custom wrong") do
test do |const|
eval(const)
end
end

x.report("active support implementation") do
test do |const|
names = const.split('::')
names.shift if names.empty? || names.first.empty?

constant = Object
names.each do |name|
constant = constant.const_defined?(name, false) ? constant.const_get(name) : constant.const_missing(name)
end
constant
end
end
end




And the results for Ruby 1.9.2 are:


Rehearsal --------------------------------------------------
custom ok 5.220000 0.020000 5.240000 ( 5.412122)

custom wrong 4.550000 0.020000 4.570000 ( 4.716120)

active support 1.560000 0.000000 1.560000 ( 1.597956)
implementation
---------------------------------------- total: 11.370000sec

user system total real
custom ok 5.180000 0.000000 5.180000 ( 5.273098)

custom wrong 4.450000 0.030000 4.480000 ( 4.547156)

active support 1.570000 0.000000 1.570000 ( 1.576236)
implementation