Pages

Monday, December 05, 2011

Include versus extend

I found the following definition for both in http://marakana.com/bookshelf/ruby_tutorial/modules.html very helpful.
  • include - mixes in a module into the class' objects (instantiations)
  • extend - mixes in a module's into self and the module's methods are available as class methods

I have also posted the question which ultimately leads to finding out the differences between include and extend in the rspec google group.

I wrote a few test scripts to learn about this more.

Include - usage of method as an object method is successful


#!/usr/bin/ruby

module Helper
  def help
    'helper method is valid'
  end
end

class Baz
   include Helper
end

puts 'Calling the class method in a chain: ' + Baz.new.help.to_s # => :avalable

bazzer = Baz.new
puts 'Calling the class method within an object: ' + bazzer.help.to_s

Results

[amalthea]$ ./include.rb
Calling the class method in a chain: helper method is valid
Calling the class method within an object: helper method is valid


Never use 'include' in the object as it's invalid.
Here's what I meant:



#!/usr/bin/ruby


module Helper
  def help
     :available
  end
end


class Bar
end


bar = Bar.new
bar.include(Helper)  # <--  this is not valid.
bar.help


Extend

#!/usr/bin/ruby

module Helper
  def help
    'helper method is called'
  end
end

class Baz
   extend Helper
end

puts 'When called as a class method, it works and the string is received: ' + Baz.help.to_s

puts rescue Baz.new.help

Results

When called as a class method, it works and the string is received: helper method is called

From the script above, the call to the module's method, help does not work and throws an exception (which I have put in rescue to stop the script from failing) because when extend is used, the module's methods will only be available as a class methods. 

Saturday, October 22, 2011

D'addarrio has launched a new string, EXP stating it outlasts Elixir in terms of clarity.

Many thanks to my good friend, Sam who notified me that the shop he works for is actually putting these on for free. As my lovely EM 325C Maton has not seen the light of day since it was last played last year, I figured this was the opportunity it deserved.







 After a quick call to my buddy, Walter, we made way to Cranbourne music, Blackburn this morning to get our acoustic guitars restrung. His of course, is a nice hand made Cole Clark form the early days of the company and needed a restring.
  The first impression of the strings was that they were only about 80% as bright as the Elixirs when new but if their clarity lasts longer, why not?

 I was of course very impressed with the guys in Cranbourne music, Blackburn particularly Ryan who restring my guitar. When he removed the existing strings, he also took the opportunity to help me clean up the frets and reseated the string holders (sorry, I can't remember what you call those 'ball' like string holders at the end of the bridge).
 Next month, they are going to restring electric guitars for free with D'addarrio electrics. As an ernie ball extra slinky fan, I do want to try new strings out. Have used D'addarrio many years ago on my SG but have never with my strat. It will be interesting. Email me and I can let you know what the date will be for the free electric strings fitting :)

 Overall, a big thank you to Cranbourne music and Sam the man :)
Bought my amps, fender hard case, Maton and accessories from them since 2006 and have never ever been disappointed. Keep rockin', guys!

Friday, October 14, 2011

I just read a bit more on RSpec's expectation matchers : should, should_not

should - It's being used like a connector. For example, if a GET request was made to the index of a resource's controller,

  fact: the resulting page would have the string, 'I love rails'
  spec:

  1. the spec would therefore expect to have the string, 'I love rails' in it
  2. we would write the spec as follows:
       request.should contain('I love rails')




should_not - it's the 'negative' version of should. This means we need not use 'not' :)


For example, if a GET request was made to the index of a resource's controller,

  fact: the resulting page will NOT have the string, 'I love rails'
  spec:

  1. the spec would therefore expect to have the string, 'I love rails' in it
  2. we would write the spec as follows to say, "we do not expect the resulting request object to have the string, 'I love rails' in its contents":
       request.should_not contain('I love rails')




Here's also another article which speaks of this well.

Gordon Yeong :)
Sequence of calls in rspec
                
 Example:
        describe "creates a new brand entry" do

            puts "I am defined BEFORE the before hook"

            before(:each) do
                puts "I am a statement defined in the before(:each) hook..."
            end

            puts "I am defined AFTER the before hook"

            login_admin_user
            it "assigns a new brand as @brand" do
                get :new
                assigns(:brand).should be_a_new(Brand)
            end

Result:

I am defined BEFORE the before hook
I am defined AFTER the before hook
....I am a statement defined in the before(:each) hook...
..........

Finished in 1.61 seconds
14 examples, 0 failures


Statements defined in before hooks will be run right before any specs are ruined. This means that if you defined statements before the statements in the before hook, those statements will run first.


To bang or not to bang?

In ruby, the bang (!) symbol is used as a convention for methods.
The general rule of thumb is use bang(!) when the method will modify its argument(s).

Refer to the following extract from the book, 'the well grounded rubyists'. It has a very clear illustration.

Here's another article which speaks on when to use ! in rails.

Wednesday, September 28, 2011


How to change the data type for a given columns using Migrations


I have a users database table. There's an attribute, 'admin' which reflects if a given user is an administrator or not. It's now time to implement features in the application which would act based on whether a user is an administrator or not. While we could have got away with the admin attribute being an integer of either zero or one, setting it as a boolean data type would be better suited to the nature of the attribute being used.

1) generate a new migration

[rails3]$ rails generate migration change_data_type_for_admin_in_users_table
      invoke  active_record
      create    db/migrate/20110927235341_change_data_type_for_admin_in_users_table.rb


2) edit the migration file and use the change_column() method. This method does allow options to
set the default value of the attribute. In this case, I set it to false such that all new users are not administrators by default
Notice that I deleted the self.down method definition. This is because in the case of a db rollback, nothing needs to be done to this attribute.
I would expect the user database table to be dropped and that's it.


class ChangeDataTypeForAdminInUsersTable < ActiveRecord::Migration  def self.up        change_column(:users, :admin, :boolean, :default => false)  endend



3) run the migration


[rails3]$ rake db:migrate
==  ChangeDataTypeForAdminInUsersTable: migrating =============================
-- change_column(:users, :admin, :boolean, {:default=>false})
   -> 0.3049s
==  ChangeDataTypeForAdminInUsersTable: migrated (0.3052s) ====================
s_table.rb$ git add db/migrate/20110927235341_change_data_type_for_admin_in_user


4) done

Tuesday, September 20, 2011

How to include devise test helpers in your rails 3 controller specs (rspec2)
including devise test helpers in your controllers would mean that you could use devise's helpers to sign_in, confirm! and so forth. For more info on the test helpers in devise, look in the devise documentation page.

Two ways:

1) put the following contents in a file, spec/support/devise.rb

RSpec.configure do |config|
 config.include Devise::TestHelpers, :type => :controller
end


2) put them in spec/spec_helper.rb

RSpec.configure do |config|
 config.include Devise::TestHelpers, :type => :controller
 config.extend ControllerMacros, :type => :controller # I'm using factory girl here
 config.use_transactional_fixtures = true
end

Sunday, September 18, 2011

Good summary of collections

http://www.adp-gmbh.ch/ora/plsql/coll/index.html

associative arrays

  1. think of them as hashes (like in perl)
  2. the keys can be string or int which means they need to be unique. See http://download.oracle.com/docs/cd/B19306_01/appdev.102/b14261/collections.htm#BABFACFA
nested tables
- no upper bound


varrays
-when declaring one, you'll need to define the upper bound
Triggers in pl/sql

Similar to :before, :after filters that are in ruby on rails, triggers in pl/sql are there to perform operations when certain events occur. This still sounds vague.

Take for example, we have a customer db table.

It would be helpful for us to have a trigger which runs when a deletion, insertion, update or  update on certain columns occurs to the customer db table. A typical action would be to log each action, timestamp and a comment into an audit dbtable for audit purposes to track the changes to the customer db table.

Format/syntax:

CREATE [OR REPLACE] TRIGGER <trigger name>
  {BEFORE|AFTER}
  {INSERT|UPDATE|DELETE| UPDATE OF <column list> ON <desired db table's name>
  [FOR EACH ROW]

  [WHEN  .... ] -- this is where we place more filters if we want the trigger to go to work when either an insertion/deletion/update or update on certain columns of a db table. For example, we only want to have the trigger work on Deletion statements issued on customer records for  customers who reside in 'state' = 'Melbourne, Victoria, Australia'
  [DECLARE]
      -- fit all the declaration statements here
  BEGIN

   [EXCEPTION]
 
END <trigger name>;
Packages in PL/SQL

Packages have objects (they own them as tables own their columns).
Objects can be (not limited to):

  1. packages
  2. functions
  3. variables
Think of a package in pl/sql as a logical grouping. For example, if there's a students package, it may have::
  • a package variable that reflects if the study term is open or not
  • procedures that process time table allocations ( does not need to return any value and runs after work hours in batch mode) 
  • functions that return statistics of students. For example, counts of local, interstate and overseas students in a given semester
Example:

CREATE OR REPLACE PACKAGE BODY students_pkg
IS 

   term_active  ....

   PROCEDURE allocate_timetables
   .....

   FUNCTION get_local_students_count
       ....
   RETURN count NUMBER;
       ....

   FUNCTION get_overseas_students_count
       ....
   RETURN count NUMBER;
       ....

   FUNCTION get_interstate_students_count
       ....
   RETURN count NUMBER;
       ....

  BEGIN 
     -- initialisation codes live here
     -- assign default values to objects here
     -- execute whatever logic/code here
  END students-pkg;


Outside the package, we use it...



DECLARE
    ...

BEGIN

    IF students_pkg.terms THEN
       DBMS_OUTPUT.PUT_LINE( "Number of local students in this term is " || students_pkg.get_local_students_count );
    END IF;

EXCEPTION
      ...
END;



Functions, procedures and their parameters - General concepts

The differences between functions and procedures are:



1) Functions need to be part of an expression (ie. assignment) whilst procedures can be called by themselves



Function:



DECLARE

    v_student_name students.name%TYPE

BEGIN

   
      v_student_name :=  get_student_name_function( 'student_id' => 1020283 );

END



Procedure:



   remove_graduated_students( :current_year => 2011, :current_campus => 'Clayton' );



2) Functions MUST return value(s) whilst procedures WILL NEVER EVER return anything



Format:



FUNCTION <name>

   RETURN return_datatype

IS

   ---declare all variables here

BEGIN

[EXCEPTION]

END [<name>];



3) format

FUNCTION:

FUNCTION <name>

 [

    (args)

 ]

   RETURN return_datatype

IS

   ---declare all variables here

BEGIN

[EXCEPTION]

END [<name>];



PROCEDURE:

PROCEDURE <name> 

 [

    (args)

 ]

IS

   ---declare all variables here

BEGIN

[EXCEPTION]

END [<name>];

Parameters:

 In the world of pl/sql, there are 2 types of parameters:
a) formal - this is the name of the parameter that is known to callers of the function/procedure. b) actual - the actual values that are represented by the formal parameters
Thinking in terms of a perl hash, formal parameters are keys whilst the actual parameters are the values.
Example:
FUNCTION get_total_sales 

     (   
   
          company_id IN company.id%TYPE,
     
         status          IN company.status%TYPE 
 
    ) 

  RETURN NUMBER

IS   v_total_sales NUMBER;

data type    ….  

 RETURN v_total_sales;

END 
DBMS_OUTPUT.PUT_LINE "The total sales is " || get_total_sales( :company_id => 21232, :status => 'trading' )

actual parameters: 21232 and 'trading'
formal parameters: company_id and status


Modes for parameters:

 The following modes are used when you define a procedure/function's parameters in its header section.

IN         - can only be read. Think of them as constants that cannot be mutated. This is the default mode pl/sql will assume when none is specified in your functions/procedures
OUT      - can only be written to (ie. assigned)
IN OUT  - can be read and written to. This is useful in the especially for procedures which would do processing and alter the values of certain variables as it does not return any values.

Advice: best to be clear in your parameters definition in the headers of your procedures/functions