Halaman

Sabtu, 31 Desember 2011

ubuntu 11.10 rails 3 passenger

http://ubuntuandrails.blogspot.com/2011/11/installing-rails-311-ruby-193-apache2.html

Senin, 03 Oktober 2011

install mysql2 > 0.3.6 for mysql 64bit in windows

gem install mysql2 --platform=ruby -- '--with-mysql-lib="C:\Program Files\MySQL\MySQL Server 5.5\lib" --with-mysql-include="C:\Program Files\MySQL\MySQL Server 5.5\include"'

http://dev.mysql.com/downloads/connector/c/

copy  C:\mysql-connector-c-noinstall-6.0.2-win32\lib\libmysql.dll to ruby\bin

original source: http://blog.mmediasys.com/2011/07/07/installing-mysql-on-windows-7-x64-and-using-ruby-with-it/

Senin, 04 Juli 2011

fixing option tag display none bug in webkit

The Problem

option tag using style display:none isn't hidden in browser using webkit engine (chrome, safari)
https://bugs.webkit.org/show_bug.cgi?id=8351

The workaround

using jQuery js framework with one simple function taken from jquery.extended_helper_2.6:
(function($) {
  $.fn.extend({
    /* hide select's specified option by removing the option and storing it in variable
     * this function is a workaround to fix webkit bug when hiding select's option:
     * https://bugs.webkit.org/show_bug.cgi?id=8351
     * hideSelectOptions(selector, options)
     * selector:
     * - string selector of options to hide
     * - null or undefined will not hide any options
     * - empty string will hide all options
     * - function will be ran for all options, return true to hide the options
     * options:
     * - toggleHide: true/false, activate/deactive toggle hide/show select if all options is hidden
     * - placeholder: string, add placeholder option if all options is hidden
     * usage:
     *  - $('select.certain_class').hideSelectOptions('.another_class'); // -> show previously hidden options and hide all options with 'another_class' class
     *  - $('select.certain_class').hideSelectOptions(''); // -> hide all options
     *  - $('select.certain_class').hideSelectOptions(); // -> show previously hidden options without hiding any options
     */
    hideSelectOptions: function(selector, options){
      if(!options) options = {};
      this.filter('select').each(function(){
        var $this = $(this);
        // restore previously hidden options and remove any placeholder option
        $this.append($this.data('hiddenOptions')).find('.placeholder_option').remove();

        // return if no selector specified
        if(!selector) return;
        
        // find, detach and store specified hidden options
        var hidden_options = $this.find('option');
        if($.isFunction(selector))
          hidden_options = hidden_options.deleteIf(function(){return !selector.call(this);});
        else
          hidden_options = hidden_options.filter(selector);
        $this.data('hiddenOptions',
          hidden_options
            .removeAttr('selected')
            .detach());

        // find visible options
        var visible_options = $this.find('option');

        // toggle hide/show select depend on visible option found
        if(options.toggleHide)
          $this.toggle(visible_options.length);
        if(options.placeholder && !visible_options.length)
          $this.append('');

        // select first option if no other visible option selected and trigger select change
        if(!visible_options.filter(':selected').length){
          visible_options.filter(':first').attr('selected', 'selected');
          $this.trigger('change');
        }
      });
      return this;
    }
  });
})(jQuery);

The Demonstration

Kamis, 30 Juni 2011

Additional Range method

class Range
  # return true if 2 range overlapped
  def overlap? other_range
    include?(other_range.begin) || other_range.include?(self.begin)
  end

  # return a new intersection range between two ranges
  def & other_range
    raise TypeError, "exclusive range can't be intersected with non-exclusive one" unless self.exclude_end? == other_range.exclude_end?
    new_begin = [self.begin, other_range.begin].max
    new_end = [self.end, other_range.end].min
    new_begin <= new_end ? Range.new(new_begin, new_end, self.exclude_end?) : nil
  end

  # return true if other_range is a subset in self
  def contains? other_range
    if !exclude_end?
      include?(other_range.begin) && include?(other_range.end)
    elsif self.begin.respond_to?('>=')
      self.begin <= other_range.begin && self.end.send(other_range.exclude_end? ? '>=' : '>', other_range.end)
    else
      raise TypeError, "can't determine inclusion of range with this type of members"
    end
  end

  # return true if self is a subset of other_range
  def within? other_range
    other_range.contains? self
  end

  # return length of the range (only for subtract-able range)
  def length
    self.end.respond_to?('-') ? self.end - self.begin : nil
  end

  # return next range with same span (only for subtract-able and add-able range)
  def succ allow_touch=false
    return nil unless self.end.respond_to?('-') && self.end.respond_to?('+')
    new_begin = allow_touch || exclude_end? || !self.end.respond_to?(:succ) ? self.end : self.end.succ
    new_end = new_begin + length
    Range.new(new_begin, new_end, exclude_end?)
  end

  # return previous range with same span (only for subtract-able and add-able range)
  def pred allow_touch=false
    return nil unless self.end.respond_to?('-') && self.begin.respond_to?('+')
    new_end = allow_touch || exclude_end? || !self.begin.respond_to?(:pred) ? self.begin : self.begin.pred
    new_begin = new_end - length
    Range.new(new_begin, new_end, exclude_end?)
  end
end

Selasa, 28 Juni 2011

array flatten with level for ruby 1.8.7

straight to the code:
class Array
  alias_method :orig_flatten, :flatten
  
  def flatten level=nil
    if level.is_a?(Integer)
      temp_arr = clone
      level.times{ |i| temp_arr = temp_arr.inject([]){|s,v| v.is_a?(Array) ? s.concat(v) : s << v} }
      temp_arr
    else
      orig_flatten
    end
  end
end

of course although untested i'm sure it will have worse performance than the original flatten in ruby 1.9.2, but better than nothing right? ;)

ruby array to hash method

update 2012-12-21:
you should use flat_map instead of flatten, i'm too lazy to update the code though.. :P

we can convert hash to array easily using .to_a method for example:
hsh = {:a => 1, :b => 2, :c => 3}
arr = hsh.to_a # -> [[:a, 1], [:b, 2], [:c, 3]]

but there's no built in method to reverse that, there's no .to_hash instance method for array.

to solve that i added a simple instance method for array:
class Array
  def to_hash values=nil
    Hash[*(values.is_a?(Array) ? self.zip(values) : self).flatten(1)]
  end
end

hsh = {:a => 1, :b => 2, :c => 3}
arr = hsh.to_a # -> [[:a, 1], [:b, 2], [:c, 3]]
arr.to_hash == hsh # -> true
[:a,:b,:c].to_hash [1,2,3] # -> {:a => 1, :b => 2, :c => 3}

a little precaution, flatten(1) will not work properly in ruby 1.8.7 or older, therefore it won't be possible to create hash with array as key or value. but there's a simple workaround for that by overriding array flatten method to behave like ruby 1.9.2 in my next post :)

useful online tools for web programming

  • Regex for ruby: http://www.rubular.com/
  • strftime: http://strfti.me/
  • css gradient generator: http://www.colorzilla.com/gradient-editor/
  • css validator: http://jigsaw.w3.org/css-validator/
  • css rounder corner generator: http://a.deveria.com/roundgen/
  • 7 great js resources (not really a tool but useful): http://mashable.com/2011/07/03/7-great-javascript-resources

will be updated as i found another tools

Sabtu, 11 Juni 2011

Rails general coding style

Code:

# somethings_controller.rb
def create
  @something = Something.new params[:something]
  @something.save!
  if @something.some_state?
    @something.initialize_for_some_state
  end
  redirect_to success_url
rescue
  render :action => "failed"
end

Hint:

  1. should avoid rescue without specifying the exception, in above code, use
    rescue ActiveRecord::RecordInvalid
  2. better yet, don't use any rescue at all, use save instead of save! with some if
  3. post processing should be done in callback.
    after_create {|something| something.initialize_for_some_state if something.some_state}

Better Code:

# somethings_controller.rb
def create
  @something = Something.new params[:something]
  if @something.save
    redirect_to success_url
  else
    render :action => "failed"
  end
end

Code:

# somethings_controller.rb
def show
  @something = Something.find(:first, :conditions => "user_id = #{current_user.id} AND id = #{params[:id]} AND name = #{params[:name]}")
  respond_to do |format|
    format.html
    format.js do
      render :js => "$('#container').html('#{escape_javascript(render :partial => "something", :object => @something)}');"
    end
    format.json do
      render :json => @something.to_json
    end
  end
end

Hint:

  1. SQL injection warning! never use data from params or from user input directly in sql code. use something like this instead:
    :conditions => ["user_id = #{current_user.id} AND id = ? AND name = ?", params[:id], params[:name]]
  2. using model relation and dynamic finder you can avoid the conditions entirely
    @something = current_user.somethings.find_by_id_and_name params[:id], params[:name]
  3. you should check if nothing found (@something is nil)
  4. this is just my opinion, but in most case i'll avoid using respond_to, instead i'll use 3 different view files: show.html.erb, show.js.erb, show.json.erb. rails will automatically use the correct view.

Better Code:

# somethings_controller.rb
def show
  @something = current_user.somethings.find_by_id_and_name params[:id], params[:name]
  render_invalid "not found" if @something.nil? # read about render_invalid in http://tech.maysora.com/2010/12/rails-renderinvalid-method.html
end


to be continued about model

Rabu, 01 Juni 2011

Counting sub-string occurrence in a string

Once upon a time.. I need a way to count number of occurrence of certain sub-string (not exclusively words) inside a string.

For example, string "Aya Hirano is the best seiyuu in the world! She was mostly known as her role as Haruhi." I wanted to know how many times string "he" occurred in there.
The result should be 4, 2 in the, 1 in She and 1 in her.

By using scan method we can do that easily:
class String
  def substr_count(pattern)
    self.scan(pattern).length
  end
end

"Aya Hirano is the best seiyuu in the world! She was mostly known as her role as Haruhi.".substr_count("he") # -> 4
"Aya Hirano is the best seiyuu in the world! She was mostly known as her role as Haruhi.".substr_count(/(!|\.|\?)/) # -> 2 -> counting sentences? :D

Too simple to become share-worthy article I guess.. :P

Selasa, 03 Mei 2011

Aborting AJAX Request

For some functions like autocomplete, usually we send ajax request whenever user stop typing (by using timeout), but if the request takes a long time to finish, user might sending another request while the previous one isn't done yet, in worst case scenario this might cause the requests complete order messed up therefore the result will be invalid.

We can prevent this by aborting previous ajax request before sending a new one.
XMLHttpRequest object have abort() function we can use for that purpose, documented here:
https://developer.mozilla.org/en/XMLHttpRequest#abort

in the following jquery script, i have a 2 text fields sending ajax request onkeyup that always completed in 2 seconds and adding the inputted text in the result div, the first one will have stackable ajax request, and the other one will prevent ajax request stacking by using abort

Senin, 14 Maret 2011

cookie operation functions

function setCookie(c_name,value,exdays){
  var exdate=new Date();
  exdate.setDate(exdate.getDate() + exdays);
  var c_value=escape(value) + ((exdays==null) ? "" : "; expires="+exdate.toUTCString());
  document.cookie=c_name + "=" + c_value;
}

function getCookie(c_name){
  var i,x,y,ARRcookies=document.cookie.split(";");

  for (i=0;i<ARRcookies.length;i++){
    x=ARRcookies[i].substr(0,ARRcookies[i].indexOf("="));
    y=ARRcookies[i].substr(ARRcookies[i].indexOf("=")+1);
    x=x.replace(/^\s+|\s+$/g,"");
    if (x==c_name){
      return unescape(y);
    }
  }
}

function removeCookie(c_name){
  setCookie(c_name, '', -1);
}

Senin, 07 Maret 2011

international saimoe league voting

my voting result: