Wednesday, 27 November 2013

Configuration in ruby gem

This article tells about How to set default configuration in your ruby gem and how to override default configuration.

Suppose you want to set default parameters for gem like environment, version, access_token, etc which will be set inside gem. At the same time You have created initialize in rails application from which you  want to achieve custom configuration. Custom configuration may or mayn't overcome default configuration as per our requirement.

Lets consider, your gem have following structure



gem_name
    |-- Gemfile
    |-- lib
    |   |-- generators
    |   |   `-- gem_name
    |   |       |-- install_generator.rb
    |   |       `-- templates
    |   |           `-- initializer.rb
    |   |-- gem_name
    |   |   |-- configuration.rb
    |   |   |-- test_file1.rb
    |   |   |-- test_file2.rb
    |   |   `-- version.rb
    |   `-- gem_name.rb
    |-- LICENSE.txt
    |-- gem_name-1.0.0.gem
    |-- gem_name.gemspec
    |-- Rakefile
    `-- README.md

1) Set Default Configuration

create  file with name configuration.rb inside lib/gem_name. So the gem structure will be 

gem_name
    |-- lib
    |   |-- gem_name
    |   |   |-- configuration.rb
    |   |   |-- test_file1.rb
    |   |   |-- test_file2.rb
    |   |   `-- version.rb
    |   `-- gem_name.rb
    |

Copy following content to configuration.rb file



    module GemName
      class Configuration

        attr_accessor :access_token
        attr_accessor :endpoint

        DEFAULT_ENDPOINT = 'http://example.com'

        def initialize
          @endpoint = DEFAULT_ENDPOINT
        end
      end
    end



Above code will create one configuration class with setting getter, setter method for our configuration parameters.

We can also define constant as DEFAULT_ENDPOINT
Initialize method will initialize class object with default parameter value. This object of configuration class will act as building block of configuration of gem.

2) Create configuration object

Open gem_name.rb. It will have content something like below


    class GemName

      def method1
      end
  
      def method2
      end
    end


Now create configuration method which will create configuration object



    class GemName

      def configuration
          @configuration ||= Configuration.new
      end

      def method1
      end
  
      def method2
      end
    end



Well you have created the configuration object with all the default parameter.
So, access parameter inside gem_name.rb  Just use

@configuration.endpoint

It will give default value of parameter endpoint written in configuration class initialize method.
Here it is 'http://example.com'

3) Set Custom configuration from initializer inside rails application

Now we will allow application to write inside our configuration object which we created above.
So we will use
 
  attr_writer :configuration

Then create anoter action configure method in GemName class which will write data in configuration object

So, GemName class looks like



    class GemName

       attr_writer :configuration

        def configure
           yield(configuration)
         end

       def configuration
           @configuration ||= Configuration.new
       end

       def method1
       end
  
       def method2
       end
    end



That's over from Gem.

Now inside initializer in rails application just past below code


GemName.configure do |config|
  config.access_token = "1234567896"
end



Well everything is fine.

Now access custom configuration in gem_name.rb with

configuration.access_token

which will return value of access_token from initializer.

That's it...

Tuesday, 26 November 2013

Devise : Redirect User To Sign In If Password Token Invalid

Devise has "forget your password?" link on sign in page.

 When user click on forget password link Devise ask for email. It will send password reset link in mail to the valid email address. Every password reset link has reset password token associated with it.

Following reset password link in mail, User has been asked to fill reset password form with fields new password and confirm password. On submitting, user reset its password successfully.

But What happen when User followed expired reset password link?
Still User has been presented with the Reset Password Form with new password and confirm password input field. When user submit the reset password form with valid data, then that devise gives error message "Password token INVALID".

How can redirect User to sign in page or any another page(action) if User comes with invalid token??

Its very easy with devise.

We need to override Devise password controller as follow.

1) Create Password Controller
rails g controller Passwords
This will generate password controller in your rails application.

2) Override with devise password controller
class PasswordsController < Devise::PasswordsController
  def edit
    self.resource = resource_class.find_or_initialize_with_error_by(:reset_password_token, params[:reset_password_token])
    if !resource.errors.empty?
      flash[:alert] = "Password token is invalid"
      redirect_to new_session_path(resource_name)
    end
  end
end
Here we are overriding edit action. In edit, we are checking if devise token are valid.

If its valid then we  will not get any error in resouce and we will display Reset Password Form.
If its invalid the we will get some error in resource and we will redirect user to sign in page or replace new_session_path with whatever action you want to replace.

3) Update routes file

  devise_for :users, :controllers => {:passwords => "passwords"}

This will force to use our password controller instead of devise password controller

Thats it.







REST API Call with NodeJS

var http = require('http');
                   // catch data to be sent
data = {"foo":"bar"}

// parsing data
jdata = JSON.parse(data);

// create the JSON object
jsonObject = JSON.stringify(jdata);

// prepare the header
var postheaders = {
    'Content-Type' : 'application/json',
    'Content-Length' : Buffer.byteLength(jsonObject, 'utf8')
};

// the post options
var optionspost = {
    host : 'localhost',
    port : 3001,
    path : '/error_requests',
    method : 'POST',
    headers : postheaders
};

console.info('Options prepared:');
console.info(optionspost);
console.info('Do the POST call');

// do the POST call
var reqPost = http.request(optionspost, function(res) {
    console.log("statusCode: ", res.statusCode);
    console.log("headers: ", res.headers);
    res.on('data', function(d) {
        console.info('POST result:\n');
//         process.stdout.write(d);
        console.info(d);
        console.info('\n\nPOST completed');
    });
});
// write the json data
reqPost.write(jsonObject);
reqPost.end();
// handle error
reqPost.on('error', function(e) {
    console.error(e);
});
For more details, you can have look on Node JS Documentation 

Data Passing Between Two Programming Languages : Command Line Approach

This blog tries to explain the way to pass the data between two programs written in two different programming languages.

There might be many approach to pass data between two program written in different programming languages. Some of them are

1) Client-Server model
    In this approach, one program up the server on particular port and another program in another  language pass socket on that port.

2) File-store model
    In this approach, one program write data to file and another program read data from that file. So, file act as common sharing center for both program

3) Database model
    In this approach, one program write data to database like MySQL, DB2, Oracle and another program  read data from database. In this both program has to create connection to database.

Above all approach are well and good but each has its own cause and prone. Here We will discuss command line approach to pass data between two programming languages.

I am taking ruby and node as two different languages to pass data.
Lets first see what do we mean by command line argument. We are considering ruby language for the same.

What is command line argument?

Command-line arguments are given after the name of a program in command-line operating systems like DOS or Linux, and are passed in to the program from the operating system. On the command-line, any text following the name of the script(program) is considered a command-line argument.

Example :
Create file test.rb and write following lines into it.
ARGV.each do|a|
  puts "Argument: #{a}"
end

This will catch command line argument and print them.
Run this file as
ruby test.rb test1 test2
Here test1 and test2 are cla. Command pass cla to file and file catch cla in ARGV and process them as array give output
Argument: test1
Argument: test2
Now we are clear with command line argument. 

Pass data between ruby program and node program

Consider we have two files cla.rb and cla.js.
cla.rb represent ruby program and cla.js represent node program. Both files are initially empty and are in same directory.

Ruby Program has data variable holding data to be pass to node program.
data = {foo: "bar"}
Now convert data to json to get string out of it with ruby josn library
Require json library at the top of program with
require "json"
Convert data to json with to_json method
jdata = data.to_json
This will generate json of data and store it to jdata variable as below

"{\"foo\":\"bar\"}"

Now its time to pass it to node program as command line argument.
But before that use Shellwords library's escape method on jdata. The double quotes are removed by the shell before passing it. To prevent shell from doing so we use Shellwords library as follow

require "shellwords"
Shellwords.escape(jdata)

Lets catch cla.js file absolute path as below

node_handler = File.join(File.dirname(__FILE__), "cla.js")

Ruby use  `` to execute shell command. We need this to run node program from ruby program.
Execute shell command to run node program and pass jdata as cla to node program.

`node #{node_handler} #{Shellwords.escape(jdata)}`

So the final program looks like as below.

#cla.rb
# require libraries
require "json"
require "shellwords"

# data to be passed
data = {foo: "bar"}

# data in json formate
jdata = data.to_json

# absolute path for cla.js
node_handler = File.join(File.dirname(__FILE__), "cla.js")

# execute node program with jdata as command line argument
cmd = `node #{node_handler} #{Shellwords.escape(jdata)}`

Here we are done with our ruby side.

Now in node program we will first catch the command line argument

var data = process.argv[2];

Parse the json data

jdata = JSON.parse(data);

We can print the json with

console.error(jdata)

So, final node program look like

// cla.js
// catch the data from command line argument
var data = process.argv[2];

// parsing data
jdata = JSON.parse(data);
console.error(jdata);

Lets have quick review what we exactly did till now

In Ruby,
1) Catch data in variable
2) Convert data to json
3) Apply escape method of Shellword library on json
4) Execute system command to run node program passing data through cla

In Node,
1) Catch the data thought cla using ARGV
2) Parse it through JSON.parse()

So, we have passed the data between two programming languages with command line approach.

Alias and alias method chain

alias_method

This method creates the alias(duplicate name) of the method


class Klass
  def a
    puts "alphabates"
  end

  alias_method :b, :a
end

Klass.new.a
=> alphabets

Klass.new.b
=> alphabets



Now, lets see the actual usage of alias_method

class Klass
  def foo
    puts "Inside foo"
  end

  def foo_with_feature
    puts "Calling Method..."
    foo_without_feature
    puts "... Method Called"
  end

  alias_method :foo_without_feature, :foo
  alias_method :foo, :foo_with_feature
end


Klass.new.foo
=> Calling Method...
Inside foo
...Method Called

Klass.new.foo_without_feature
=> Inside too



In above code, I have defined the class with foo() method. Later I have think of extending the foo() method. So I have created the foowithfeature() method and add some extra functionality in foowithfeature method.

Now, I want to execute the foowithfeature() method by the calling foo() method. So I have create alias method as "aliasmethod :foo, :foowithfeature". But at the same time, I doesn't want to loose the contact to original foo method. So, I have created another alias method as " aliasmethod :foo, :foowithfeature".

Now look to result when I call "Klass.new.foo"
It executes foowithfeature method which internally call original foo method. So, thereby we have achieve our goal of extending the original method without replacing its actual call method.

In other words, you provide the original method, foo(), and the enhanced method, foowithfeature(), and you end up with three methods: foo(), foowithfeature(), and foowithoutfeature().

alias_method_chain

Lets make it more simple with rails. "aliasmethodchain" reduces the override to write two aliases with single line.
Note : Test below code in rails console

class Klass
  def foo
    puts "Inside foo"
  end

  def foo_with_feature
    puts "Calling Method..."
    foo_without_feature
    puts "... Method Called"
  end

  alias_method_chain :foo, :feature
end

So now we can just type aliasmethodchain :foo, :feature and we will have 3 methods: foo, foowithfeature, foowithoutfeature which are properly aliased as describe above

This kind of things are used in monkeypatching, support to previous version of gem, plugin where you extend the some method of class, catch the method call of that class, do some extra and continue with the original method execution.



References
* http://apidock.com/ruby/Module/aliasmethod 
* http://ruby.about.com/od/rubyfeatures/a/aliasing.htm 
* http://apidock.com/rails/Module/aliasmethod_chain

Monday, 25 November 2013

Ruby : Make and Publish Gem with bundler

What is Ruby Gem ?

A gem is a packaged Ruby application or library. RubyGems is the standard way to distribute Ruby applications and libraries and is available to you after you have downloaded and installed Ruby.

We can install gem with
gem install gem_name
How to create Gem ?

Lets move one step ahead and start building our first new gem. As we are going to publish it later, lets check availability of gem name on rubygems.com

1) Suppose we want to create gem with name  "test_gem". Type  below command to your terminal and wait for result.
gem list -r test_gem
We will get below result.

 *** REMOTE GEMS ***
test_gem (0.0.3)
test_gem_AF (0.0.0)
test_gem_eer (0.0.1)
test_gem_mjn (0.0.1)
test_gem_sup (0.0.0)
test_gem_Thomas (0.0.0)
test_gemeroni (1.0.0)

That mean our gem name is already been taken So lets try some thing unique.

gem list -r test_gem_ketan
We will get below result.

*** REMOTE GEMS ***



If we did not get any gem in list then our name is unique and we can continue with this name to build our gem.

Until now we just check if our gem name is available or not. Now lets start to create gem "test_gem_ketan"

2) Type below command to create sample template of out gem with bundler.
Remove test_gem_ketan with test_gem_yourname if you want gem with your name. But then dont forget to update below command as per your name.
 bundle gem test_gem_ketan
We will get below result.

      create  test_gem_ketan/Gemfile
      create  test_gem_ketan/Rakefile
      create  test_gem_ketan/LICENSE.txt
      create  test_gem_ketan/README.md
      create  test_gem_ketan/.gitignore
      create  test_gem_ketan/test_gem_ketan.gemspec
      create  test_gem_ketan/lib/test_gem_ketan.rb
      create  test_gem_ketan/lib/test_gem_ketan/version.rb
Initializating git repo in /home/webonise/StudyProjects/gems/test_gem_ketan

This will generate the basic skeleton of our gem. Go inside the gem folder with
cd test_gem_ketan
3) Lets have look on important files of gem

test_gem_ketan.gemspec

Gemspec file sets the specification of gem. The gemspec defines what’s in the gem, who made it, and the version of the gem. It’s also your interface to RubyGems.org. All of the information you see on a gem page (like jekyll’s) comes from the gemspec.

Type below command and lets have look on gemspec file.
cat test_gem_ketan.gemspec
We will get below result

# coding: utf-8
lib = File.expand_path('../lib', __FILE__)
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
require 'test_gem_ketan/version'

Gem::Specification.new do |spec|
  spec.name          = "test_gem_ketan"
  spec.version       = TestGemKetan::VERSION
  spec.authors       = ["Ketan Ghumatkar"]
  spec.email         = ["ketanghumatkar@gmail.com"]
  spec.description   = %q{TODO: Write a gem description}
  spec.summary       = %q{TODO: Write a gem summary}
  spec.homepage      = ""
  spec.license       = "MIT"

  spec.files         = `git ls-files`.split($/)
  spec.executables   = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
  spec.test_files    = spec.files.grep(%r{^(test|spec|features)/})
  spec.require_paths = ["lib"]

Replace  spec.description and spec.summary  with description and summary.
In our case, it will be


  spec.description   = %q{Test Gem Description}
  spec.summary       = %q{Test Gem Summary}


Version specifies the  current version of gem. We have create separate file to maintain version
cat lib/test_gem_ketan/version.rb
We will have result

module TestGemKetan
  VERSION = "0.0.1"
end

Now the last and most important file is test_gem_ketan.rb
Here you can write the gem code. lets simple print "something" to test it.

require "test_gem_ketan/version"
module TestGemKetan
  # Your code goes here...
  puts "Well Done. First Gem created !!!"
end

4) Now We will build gem with single command
gem build test_gem_ketan.gemspec
We will get result.

WARNING:  no homepage specified
  Successfully built RubyGem
  Name: test_gem_ketan
  Version: 0.0.1
  File: test_gem_ketan-0.0.1.gem

 5) Then we can install the generated gem locally to test it out.
gem install test_gem_ketan-0.0.1.gem


Successfully installed test_gem_ketan-0.0.1
1 gem installed
Installing ri documentation for test_gem_ketan-0.0.1...
Building YARD (yri) index for test_gem_ketan-0.0.1...
Installing RDoc documentation for test_gem_ketan-0.0.1...

6) Lets test it.


 irb                                                                  
irb(main):001:0> require 'test_gem_ketan'
Well Done. First Gem created !!!
=> true
irb(main):002:0> exit

yeee... it works

7) Now its time to publish our gem to rubygems.org

Create account at rubygems or use already existing account to push gem
 gem push test_gem_ketan-0.0.1.gem
Enter your RubyGems.org credentials.
Don't have an account yet? Create one at http://rubygems.org/sign_up
   Email:   WriteYourEmail
Password:   WriteYourPassword
Pushing gem to https://rubygems.org...
Signed in.
Pushing gem to https://rubygems.org...
Successfully registered gem: test_gem_ketan (0.0.1)

 Now check is it publish ??
gem list -r test_gem_ketan 
We will get result.

*** REMOTE GEMS ***
test_gem_ketan (0.0.1)


Cong rates. This means we have created and publish our first gem successfully.

Deleting  gem at Rubygems.org

Since our gem is for demonstration purposes only, I would like to delete my gem from RubyGems.org’s index.

Install gemcutter as below:
gem install gemcutter

Then to remove gem type
gem yank test_gem_ketan -v 0.0.1 

Yanking gem from RubyGems.org...
Pushing gem to https://rubygems.org...
Successfully yanked gem: test_gem_ketan (0.0.1)


However, the gem is still available for download for two main reasons:
  1. Other gems may have been pushed that depend on your gem.
  2. A mass deletion of important community based gems can be easily prevented.
That’s it. Thank you.