Showing posts with label ruby. Show all posts
Showing posts with label ruby. Show all posts

Monday, 16 September 2013

Metaprogramming with ruby


1) eval , #{} and their difference.

eval  is used to evaluate the string as expression.
#{} is used to delimit the expressions in a double-quoted string.

At first they both look same however there is a difference between both. Let me explain this with the help of an example.
Suppose we have a variable
exp = "2*4"
Now the output of eval(exp) will be 8
Where as output of  "#{exp}"  will be 2*4

2) instance_eval, module_eval and class_eval

instance_eval can be used to access the instance variable of an object.

For example:-
class Test
  def initialize
  @variable = "hello"
  end
end

obj = Test.new
obj.instance_eval do 
 puts @variable # Output-> hello
end
instance_eval can also be used for creating class methods

For example:-
class Test
end

Test.instance_eval do 
 def hello
   puts "hello world"
 end
end

Test.hello # output => hello world
Like instance_eval, module_eval and class_eval are used to access class variable from outside a class.
Both module_eval and class_eval operates on modules and class rather than their objects.

For Example:-
class Test
 @@variable = "hello"
end

 puts Test.class_eval(@@variable) # Output-> hello
module_eval and class_eval are also used to create new instance methods.
For Example:-
class Test
end

Test.class_eval do 
 def hello
   puts "hello world"
 end
end
obj = Test.new
obj.hello # output => hello world

3) instance_variable_get and instance_variable_set
instance_variable_get, as the name suggests, is used to retrieve the value of any instance variable.
It takes the the variable name as symbol argument

For example:-
class Test
  def initialize
  @variable = "hello"
  end
end

obj = Test.new
obj.instance_variable_get(:@variable) # Output => hello
instance_variable_set, as the name suggests, is used to set the value of any instance variable.
It takes a symbol argument as variable name and second argument which is the variable value

For example:-
class Test
  def initialize
  @variable = "hello"
  end
end

obj = Test.new
obj.instance_variable_set(:@variable,"hello world")
4) send method

send method is used to call a method of the same name as specified as the first argument(which is in symbol format)

For Example:-
@variable = "test"
puts( @variable.send(:reverse)) # this will call the reverse method for that string
You can also pass the any number of arguments after specifying the first argument which is the method name.

For Example:-
class Test
  def sum (a,b)
  return a+b
  end
end

obj = Test.new
obj.send(:sum, 4 , 5) # Output =>9
5) define_method 

This method can be used to define new methods during run time.
For Example:-
 class A
   define_method("test") do ||
     puts "hello"
   end
 end
b= A.new
b.test #output => hello
Another Example:-
Here we are also passing some arguments to the newly created method
 class Array
   define_method(:aNewMethod, lambda{ |*args| puts( args.inspect) } end
[].aNewMethod([1,2,3]) #Ouput [1,2,3]
6) remove_method

You can also remove the existing methods or method you created by using the remove_method.

For Example:-
puts("hello".reverse)
class String
remove_method(:reverse)
end
puts("hello".reverse) # Output => undefined method error!
Note: - If a method with the same name is defined for an ancestor of that class, the ancestor class method is not removed

7) method_missing


There might be the times when you may try to execute a method which is not defined, this will throw an error and cause the program to exit. To handle this situation you can write your own method called method_missing with an argument to which the missing method name is assigned.
class Test
  def method_missing (method_name)
    puts("#{method_name} do not exist")
  end
end

obj = Test.new
obj.new_method # Output = > new_method do not exist

8) Frozen Object
 
Ruby provides you a facility to freeze an object so that it cant be modified further. The object once frozen cannot be modified, if tried to do so it will raise a TypeError exception.
variable = "Hello" 
variable << "world" 
variable.freeze 
variable << " !!!" # Error: "can't modify frozen string (TypeError)"
Please note once an object is frozen it cant be be undone.

Monday, 12 August 2013

Difference between collect, select, map and each in ruby

This post is not related to rails part but the RUBY part.

To iterate over an array we generally use collect, select, map and each. As I am beginner I never actually thought what is the difference and I kept using EACH for every loop iteration. However, recently I researched a bit more about these loops and thought to share it . It might help some one I guess  :)

1) Map

Map takes the enumerable object and a block like this [1,2,3].map { |n| n*2 } and evaluates the block for each element and then return a new array with the calculated values.

so the outcome of  [1,2,3].map { |n| n*2 } will be [2,4,6]

If you are try to use map to select any specific values like where n >2 then it will evaluate each element and will output only the result which will be either true or false

so the outcome of  [1,2,3].map { |n| n>2 } will be [false, false, true]

2) Collect

Collect is similar to Map which takes the enumerable object and a block like this [1,2,3].collect { |n| n*2 } and evaluates the block for each element and then return a new array with the calculated values.

so the outcome [1,2,3].collect{ |n| n*2 } of will be [2,4,6]

If you are try to use collect to select any specific values like where n >2 then it will evaluate each element and will output only the result which will be either true or false

so the outcome of  [1,2,3].collect { |n| n>2 } will be [false, false, true]

3) Select

Select evaluates the block with each element for which the block returns true.

so the outcome of  [1,2,3].select { |n| n*2 } will be [1,2,3]

If you are try to use select to get any specific values like where n >2 then it will evaluate each element but returns the array that meets the condition

so the outcome of  [1,2,3].select{ |n| n>2 } will be [3]

4) Each

Each will evaluate the block with each array and will return the original array not the calculated one.
so the outcome of  [1,2,3].each{ |n| n*2 } will be [1,2,3]

If you are try to use each to select any specific values like where n >2 then it will evaluate each element but returns the original array

so the outcome of  [1,2,3].each { |n| n>2 } will be [1,2,3]

Wednesday, 20 February 2013

Giving name to excel sheet while exporting it- rails 3

You may want to give file name to your excelsheet when you are exporting it. Suppose you want to give the todays date and time as its name. Then do the following:

Suppose export is the method in which you have written the code for exporting excel sheet then do the following:


    def export
       time = Time.now
       time.strftime("%Y-%m-%d %H:%M:%S")
 
      respond_to do |format|
      format.html

      format.xls { headers["Content-Disposition"] = "attachment; filename=\"#{time}"+".xls"}
    end

Monday, 21 January 2013

Importing an excelsheet -ruby on rails

I recently used roo gem for importing an excel sheet into your ruby on rails application.
Below are the steps for it :

Step 1: Add the line gem 'roo' in your gem file
Step 2: Run bundle install
Step 3:Add a method in your controller :-
Suppose your controller name is Decoration
          
def import
  Decoration.import(params[:file])
  redirect_to root_url, notice: "decorations imported."
end

Step 4: In your model add the import method as follows:
Here your model name is Decoration

def self.import(file)
  spreadsheet = open_spreadsheet(file)
  header = spreadsheet.row(1)
  (2..spreadsheet.last_row).each do |i|
    row = Hash[[header, spreadsheet.row(i)].transpose]
    decoration = find_by_id(row["id"]) || new
    decoration.attributes = row.to_hash.slice(*accessible_attributes)
    decoration.save!
  end
end

def self.open_spreadsheet(file)
  case File.extname(file.original_filename)
  when ".csv" then Csv.new(file.path, nil, :ignore)
  when ".xls" then Excel.new(file.path, nil, :ignore)
  when ".xlsx" then Excelx.new(file.path, nil, :ignore)
  else raise "Unknown file type: #{file.original_filename}"
  end

Step 5 :In the config/application.rb file add this line:

require 'iconv'
 

Step 6: Add this this line to your routes.rb file

resources :decorations do
  collection { post :import }
end

Step7: Add the interface for importing the excel file using below lines:

<%= form_tag import_decorations_path, multipart: true do %>
  <%= file_field_tag :file %>
  <%= submit_tag "Import" %>
<% end %>


Note: Only. xls file can be imported using the above method.

Tuesday, 15 January 2013

Testing paperclip with rspec

This post cover the basic testing of paper clip gem in the controller. Since I am new to rspec so I may not be able to cover it in detail with many test cases now but for beginners, I hope its useful.

Suppose you are testing the new function of your controller then the steps will be like this:

  1.  Add a describe in your decorations_controller_rspec.rb.
    Note: Decoration here is the name of my controller, which creates a decoration with a name, year of that decoration and expense.Expense here is an excel sheet which is getting uploaded through paperclip gem.

    describe "#new" do
        it "must take 4 parameter and returns a decoration object" do
         get "new"
            @decorations=Decoration.new(:name=>'decoration',:year=>'2012',:zone_id=>'1',:expense=> File.new(Rails.root + 'spec/fixtures/test.xls'))
           @decorations.should be_an_instance_of Decoration
        end
    end
  2. Create a folder fixtures inside spec directory of your application and add any xls file suppose test.xls. 
  3. Its done. You rspec will pass the test case.