mercredi 29 mars 2023

How to pass header X-Request-Start to Rails app under Apache + Passenger

I need to pass header X-Request-Start to my Rails application. I add the header to the request using following directive in Apache configuration file:

<VirtualHost *:443>
  ...
  RequestHeader add X-Request-Start "%t"
  CustomLog "/var/log/apache2/access.log" "%v %l %u %t \"%r\" %>s %b \"%{X-Request-Start}i\""
  ...
</VirtualHost>

The 2nd line is there to save the header value to a log file to verify, that the header is successfully added.

In my Rails application I expect to have header HTTP_X_REQUEST_START available in a hash request.env. But the header is not there! I've found that Passenger removes it from some stupid performance problems... I also found that Nginx server support directive passenger_pass_header, which forces the Passenger to keep the header in a request. Under Apache there is no similar directive. I've found keyword always, which could be added to the directive RequestHeader in Apache config. Unfortunately this directive work only with the directive Header. The directive RequestHeader doesn't know this keyword.

Does anyone know relevant way how to force Passenger to pass the header to my Rails app?

My environment: Ubuntu 18.04.2 LTS, Apache/2.4.29, Phusion Passenger 6.0.2, Rails 3.2, Ruby 1.9.3 p551.

I spend already 2 days with this problem with no success. I tried to ask for help also Chat GPT :-), but its answers were buggy. At the end I had to inform GPT about correct result! :-o

dimanche 26 mars 2023

How can I make recursion works correctly in Ruby?

I'm trying to code a Mastermind game with Ruby. It's an exercise from https://www.theodinproject.com/lessons/ruby-mastermind.

I build a method #make-guess that loops 4 times taking input from the user and validating it i.e making sure that the input is included in #BALL array.

For that, I declared a condition if the input is included in the #BALL array, append it to an array #guess, and else, call the function again (recursion).

The problem is when an input is not included, the function #make-guess loops more than 4 times. Here is the code I'm working on:

class MasterMind
  BALLS = ['r', 'g', 'o', 'y', 'v', 'm']

  comp_selection = BALLS.sample(4)

  def make_guess
    guess = []
    until guess.length == 4
      puts "Guess the computer's combination from: 'r', 'g', 'o', 'y', 'v', 'm'"
      value = gets.chomp
      if BALLS.include?(value)
        guess.append(value)
      else
        puts 'Selection not in the combination, try again'
        make_guess
      end
    end
    guess
  end

end

master = MasterMind.new
puts master.make_guess

mardi 21 mars 2023

Different ways of using custom Time zone select option in ROR

Different ways of using custom Time zone select option in ROR

1. Using TZInfo::DataTimezone
2. Using TZInfo::Timezone
3. Customize priority in select option using time_zone_select
4. Select option to get "GMT +.." Time zone option using ActiveSupport::TimeZone

Note:
1. I have used gem 'bootstrap-select-rails' for class= selectpicker.
2. Search option is introduced in options

"data-live-search": "true"

3.prompt: '--Select timezone--' is added for user prompt.

Different ways of using custom Time zone in ROR1. Using TZInfo::DataTimezone

slim code snippet

= select_tag 'country[time_zone]', options_for_select(TZInfo::DataTimezone.all_country_zone_identifiers {|c| TZInfo::DataTimezone.get(ActiveSupport::TimeZone[c]) }), class: 'form-control'

Output of above
<select name="country[time_zone]" id="country_time_zone" class="form-control"> <option value="Europe/Andorra">Europe/Andorra</option> <option value="Asia/Dubai">Asia/Dubai</option>..... </select>

  1. Using TZInfo::Timezone
    slim code snippet
= select_tag 'country[time_zone]', options_for_select(TZInfo::Timezone.all {|c| Time.zone(c.offset)}), class: 'form-control'

Output of above
<select name="country[time_zone]" id="store_time_zone" class="form-control"><option value="Africa - Abidjan">Africa - Abidjan</option><option value="Africa - Accra">Africa - Accra</option>..........</select>

3. Customize priority in select option using time_zone_select

= time_zone_select("country", :time_zone,[ActiveSupport::TimeZone['Singapore'],ActiveSupport::TimeZone['Beijing'],ActiveSupport::TimeZone['Chongqing'],ActiveSupport::TimeZone['Hong Kong'],ActiveSupport::TimeZone['Irkutsk'],ActiveSupport::TimeZone['Kuala Lumpur'],ActiveSupport::TimeZone['Perth'],ActiveSupport::TimeZone['Taipei'],ActiveSupport::TimeZone['Ulaanbaatar']],options = {prompt: '--Select timezone--', value: :id}, html_options = {class:'form-control selectpicker', required: true, "data-live-search": "true"})

output

<select class="form-control selectpicker" required="required" data-live-search="true" name="country[time_zone]" id="country_time_zone" tabindex="-98"><option value="">--Select timezone--</option><option value="Singapore">(GMT+08:00) Singapore</option>.........</select>

4. Select option to get "GMT +.." Time zone option using ActiveSupport::TimeZone

= select_tag 'country[time_zone]', options_for_select(ActiveSupport::TimeZone.all{ActiveSupport::TimeZone['Singapore']}, f.object.time_zone), class: 'form-control selectpicker', "data-live-search": "true", prompt: '--Select timezone--'

output
<select name="country[time_zone]" id="store_time_zone" class="form-control selectpicker" data-live-search="true" required="required" tabindex="-98"><option value="">--Select timezone--</option><option value="(GMT-12:00) International Date Line West">(GMT-12:00) International Date Line West</option><option value="(GMT-11:00) American Samoa">(GMT-11:00) American Samoa</option></select>

mardi 14 mars 2023

DOMException on calling navigator.clipboard.readText() when implementing Clipboard button

I'm trying to implement a copy to clipboard button but keep on getting this error. I have the below code in my ruby on rails app.

import { Controller } from "@hotwired/stimulus"

// Connects to data-controller="copy"
export default class extends Controller {
  static targets = ["text", "button"]
  connect() {
  }
  copyText() {
    // Copy the text inside the text field
    navigator.clipboard.writeText(clippy_button.href).then(function(x) {
      alert("Link copied to clipboard: " + clippy_button.href);
    });
  }
}

div data-controller="copy" class="p-4 mb-4 mt-4 border rounded chat-hint-box">
  <%= turbo_stream_from "channel_#{@uuid}" %>
  <div data-copy-target="text" id="ai_output">
    <%= render partial: "ai/output", locals: { generated_idea: "" } %>
  </div>

lundi 13 mars 2023

How can I add a background image to an input in a simple_form_for - Rails

I'm creating simple form in rails for create a new account, each account must has their icon. but I don't know how can I use the icon association to add in the input_html their respective icon image.

I'm trying to display the list of icons, the Icons has an url and their has a foreign key in the accounts, so I'm using this:

<%= simple_form_for [@account], data: { account_card_target: "form" } do |f| %>
        <div class="form-inputs">
          <%= f.input :account_name %>
          <%= f.input :account_type,
                      collection: ['***', '***', '***', '***'],
                      prompt: "Select a type" %>
          <%= f.input :balance %>
          <%= f.input :account_number  %>
          <%= f.association :icon,
                as: :radio_buttons,
                label_method: ->(icon) { "<label class='icon-radio-label' for='my-input' style='background-image: url(#{cl_image_path(icon.url)})'></label>".html_safe },
                value_method: :id,
                input_html: { class: 'my-input', id: 'my-input' }
        %>
        </div>
        <div class="form-actions">
          <%= f.button :submit %>
        </div>
<% end %>

but in this code I'm adding the background to the label, and I wanna have the label empty and use the background image in the input.

If I use this I can add the bg image to the imput but i don't know how can I replace the 'saving_icon' for the icon.url, because I alerady try with lambda but still not working

<%= f.association :icon,
        as: :radio_buttons,
        label_method: ->(icon) { " " },
        value_method: :id,
        input_html: {
          class: "icon-radio",
          style: "background-image: url(#{cl_image_path('saving_icon')});"
        }
%>

any tip for achive this it'll be well received, thank you!

Error in Testing the User Controller: User count did not change by 1 and Expected response to be a redirect

These are the errors it shows, however, it does work on the system:

UsersControllerTest#test_should_destroy_user [/mnt/c/code/toy_application/test/controllers/users_controller_test.rb:42]:
"User.count" didn't change by -1.
Expected: 1
  Actual: 2

Failure:
UsersControllerTest#test_should_destroy_user [/mnt/c/code/toy_application/test/controllers/users_controller_test.rb:42]:
"User.count" didn't change by -1.
Expected: 1
  Actual: 2

Failure:
UsersControllerTest#test_should_get_edit [/mnt/c/code/toy_application/test/controllers/users_controller_test.rb:33]:
Expected response to be a <2XX: success>, but was a <302: Found> redirect to <http://www.example.com/login>
Response body: <html><body>You are being <a href="http://www.example.com/login">redirected</a>.</body></html>


UsersControllerTest#test_should_update_user [/mnt/c/code/toy_application/test/controllers/users_controller_test.rb:38]:
Expected response to be a redirect to <http://www.example.com/users/775686554> but was a redirect to <http://www.example.com/login>.
Expected "http://www.example.com/users/775686554" to be === "http://www.example.com/login".

user_controller.test

require "test_helper"

class UsersControllerTest < ActionDispatch::IntegrationTest
  setup do
    @user = users(:manon)
  end

  test "should get index" do
    get users_url
    assert_response :success
  end

  test "should get new" do
    get signup_path
    assert_response :success
  end

  test "should create user" do
    assert_difference("User.count") do
      post users_url, params: { user: { email: "user@example.com", name: "Example User", password: "thisfoobar", password_confirmation:"thisfoobar"} }
    end

    assert_redirected_to user_url(User.last)
  end

  test "should show user" do
    get user_url(@user)
    assert_response :success
  end

  test "should get edit" do
    get edit_user_url(@user)
    assert_response :success
  end

  test "should update user" do
    patch user_url(@user), params: { user: { email: @user.email, name: @user.name, password: "thisfoobar", password_confirmation: "thisfoobar"  } }
    assert_redirected_to user_url(@user)
  end

  test "should destroy user" do
    assert_difference("User.count", -1) do
      delete user_url(@user)
    end

    assert_redirected_to users_url
  end

end

user_controller:

class UsersController < ApplicationController
  before_action :logged_in_user, only: [:index,:edit, :update, :destroy]
  before_action :correct_user, only: [:edit, :update]
  before_action :admin_user, only: :destroy

  # GET /users or /users.json
  def index
    @users = User.all
  end

  # GET /users/1 or /users/1.json
  def show
    @user = User.find(params[:id])
    # debugger
  end

  # GET /users/new
  def new
    @user = User.new
  end

  # GET /users/1/edit
  def edit
  end

  # POST /users or /users.json
  def create
    @user = User.new(user_params)

    respond_to do |format|
      if @user.save
        log_in @user
        format.html { redirect_to user_url(@user), notice: "Welcome to the Sample App" }
        format.json { render :show, status: :created, location: @user }
      else
        format.html { render :new, status: :unprocessable_entity }
        format.json { render json: @user.errors, status: :unprocessable_entity }
      end
    end
  end

  def edit
    @user = User.find(params[:id])
  end

  # def update
  #   @user = User.find(params[:id])
  #   if @user.update(user_params)
  #     # Handle a successful update.
  #   else
  #     render 'edit'
  #   end
  # end

  # PATCH/PUT /users/1 or /users/1.json
  def update
    if @user.update(user_params)
      flash[:success] = "Profile Updated"
      redirect_to user_url(@user)
    else
      flash.now[:error] = "There was an error updating your profile."
      render :edit, status: :unprocessable_entity
    end
  end

  # DELETE /users/1 or /users/1.json
  def destroy
    User.find(params[:id]).destroy
    flash[:success] = "User deleted"
    redirect_to users_url
  end
  

  #show micropost for the user
  def show
    @user = User.find(params[:id])
    @micropost = @user.microposts.first
  end

  private
    # Use callbacks to share common setup or constraints between actions.
    def set_user
      @user = User.find(params[:id])
    end

    # Only allow a list of trusted parameters through.
    def user_params
      params.require(:user).permit(:name, :email, :password, :password_confirmation)
    end

    # Before filters
# Confirms a logged-in user.
  def logged_in_user
    unless logged_in?
      store_location
      flash[:danger] = "Please log in."
      redirect_to login_url
    end
  end

  # Confirms the correct user.
  def correct_user
    @user = User.find(params[:id])
    redirect_to(root_url) unless current_user?(@user)
  end

  # Confirms an admin user.
  def admin_user
    redirect_to(root_url) unless current_user.admin?
  end
end

user.rb

class User < ApplicationRecord
    has_many :microposts
    attr_accessor :remember_token
    before_save { self.email = email.downcase }
    validates :name, presence: true, length: { maximum: 50 }
    VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i
    validates :email, presence: true, length: { maximum: 255 },
    format: { with: VALID_EMAIL_REGEX },
    uniqueness: true
    
    has_secure_password
    validates :password, presence: true, length: { minimum: 6 }, allow_nil: true

    # Returns the hash digest of the given string.
    def User.digest(string)
        cost = ActiveModel::SecurePassword.min_cost ? BCrypt::Engine::MIN_COST :
        BCrypt::Engine.cost
        BCrypt::Password.create(string, cost: cost)
    end

    # Returns a random token for the advanced login(remember me functionality).
    def User.new_token
        SecureRandom.urlsafe_base64
    end

    # Remembers a user in the database for use in persistent sessions.
    def remember
        self.remember_token = User.new_token
        update_attribute(:remember_digest, User.digest(remember_token))
    end

    # Returns true if the given token matches the digest.
    def authenticated?(remember_token)
        return false if remember_digest.nil?
        BCrypt::Password.new(remember_digest).is_password?(remember_token)
    end

    # Forgets a user.
    def forget
        update_attribute(:remember_digest, nil)
    end
end

Gemfile

source "https://rubygems.org"
git_source(:github) { |repo| "https://github.com/#{repo}.git" }

ruby "3.2.0"

# Bundle edge Rails instead: gem "rails", github: "rails/rails", branch: "main"
gem "rails", "~> 7.0.4", ">= 7.0.4.2"

#bootstrap
gem "bootstrap", "~> 5.2.0"

# The original asset pipeline for Rails [https://github.com/rails/sprockets-rails]
gem "sprockets-rails"

# Use postgresql as the database for Active Record
gem "pg", "~> 1.1"

# Use the Puma web server [https://github.com/puma/puma]
gem "puma", "~> 5.0"

# Use JavaScript with ESM import maps [https://github.com/rails/importmap-rails]
gem "importmap-rails"

# Hotwire's SPA-like page accelerator [https://turbo.hotwired.dev]
gem "turbo-rails"

# Hotwire's modest JavaScript framework [https://stimulus.hotwired.dev]
gem "stimulus-rails"

# Build JSON APIs with ease [https://github.com/rails/jbuilder]
gem "jbuilder"

# Use Redis adapter to run Action Cable in production
# gem "redis", "~> 4.0"

# Use Kredis to get higher-level data types in Redis [https://github.com/rails/kredis]
# gem "kredis"

# Use Active Model has_secure_password [https://guides.rubyonrails.org/active_model_basics.html#securepassword]
gem "bcrypt", "~> 3.1.7"

# Windows does not include zoneinfo files, so bundle the tzinfo-data gem
gem "tzinfo-data", platforms: %i[ mingw mswin x64_mingw jruby ]

# Reduces boot times through caching; required in config/boot.rb
gem "bootsnap", require: false

# Use Sass to process CSS
# gem "sassc-rails"

# Use Active Storage variants [https://guides.rubyonrails.org/active_storage_overview.html#transforming-images]
# gem "image_processing", "~> 1.2"

group :development, :test do
  # See https://guides.rubyonrails.org/debugging_rails_applications.html#debugging-with-the-debug-gem
  gem "debug", platforms: %i[ mri mingw x64_mingw ]
end

group :development do
  # Use console on exceptions pages [https://github.com/rails/web-console]
  gem "web-console"

  # Add speed badges [https://github.com/MiniProfiler/rack-mini-profiler]
  # gem "rack-mini-profiler"

  # Speed up commands on slow machines / big apps [https://github.com/rails/spring]
  # gem "spring"
end

group :test do
  # Use system testing [https://guides.rubyonrails.org/testing.html#system-testing]
  gem "capybara"
  gem "selenium-webdriver"
  gem "webdrivers"
end

What does the error mean and how do I fix the error?

vendredi 10 mars 2023

remove_possible_method not removing the method for a module

My_module.methods returns [:local_constants, :module_exec, :class_exec, :module_eval, :class_eval, :included_modules, :include?, :name, :ancestors, :instance_methods, :public_instance_methods, :protected_instance_methods, :private_instance_methods, :constants, :const_get, :const_set, :const_defined?, :class_variables, :remove_class_variable, :class_variable_get, :class_variable_set, :class_variable_defined?, :public_constant, :private_constant, :deprecate_constant, :singleton_class?, :public_method_defined?, :method_defined?, :protected_method_defined?, :private_method_defined?, :public_class_method, :private_class_method, :<, :>, :alias_method_chain, :alias_attribute, .......]

My_module.instance_methods returns [:test_module, test_func, ....]

So when i do My_module.remove_possible_method :test_module It doesn't remove it.

If I try to call My_module.test_module it is throwing this error:

 Exception: undefined method `get_portal_redis_key' for #<Module:0x00007fea9b946>

Is ruby on rails fullstack technology? If yes, then which technologies are used in frontend and backed side

Can somebody brief me on ruby on rails is this frontend or backend, which technologies are used for the development.

As per my understand, i think its full stack technology

lundi 6 mars 2023

store the value in array and return the function ruby

item has array of hash. ex. item = [{item1},{item2},{item3}]

def function1
   item.map( other_class.call )
end

# other class will return the array which contains string
class other_class
   def call 
     #method which return arrray of strings
   end
end

currently the function1 is returning the array of array which has string values.

function1 output example [["str1"], [], ["str2"], ["str3"], ["str4","str5"]]

I want to modify the function1 which will return the array of string.

expected output = ["str1" "str2", "str3", "str4", "str5"]

Guys, any idea how can I modify the above method.

Thanks in advance.

vendredi 3 mars 2023

Retrive a specific value from json using select in ruby

I have this json value

funny = [
{
    :name=>"cf_shank_1",
    :required=>true,
    :choices=>[
        [
            "firsttttt",
            "firsttttt"
        ],
        [
            "seconddd",
            "seconddd"
        ],
        [
            "thirddd",
            "thirddd"
        ],
        [
            "fourthhh",
            "fourthhh"
        ],
        [
            "otherrrr",
            "otherrrr"
        ],
    :sections=>[
        {
            :name=>"firsttttt",
            :fields=>[
                {
                    :name=>"cf_first_kano_1",
                    :required=>false
                }
            ]
        },
        {
            :name=>"thirddd",
            :fields=>[
                {
                    :name=>"multiselect_1",
                    :required=>true
                }
            ]
        }
    ]
}]

my main goal is to find all of the names which has required=true on the basis of choice selected. and we need to fetch the value form sections. and want to store it in array.

I'm trying like this but I'm interested to know how we can modify this method or can we use some other method

value = funny[:sections].select {|x| x[:name].eql?("thirddd") }
a = value.select {|i| i[:fields][:required] }
    @mandatory_item_fields_name << a[0][:name] if a.present?
  else
    @mandatory_item_fields_name << obj[:name] if obj[:required]
  end
end

My expected answer is array values which has field name where require is true. @mandatory_item_fields_name = [ multiselect_1 ]

how we can improve the code quality here? Any help is appreciated. thanks in advance

mercredi 1 mars 2023

Ruby SFTP Client

This is my Ruby SFTP Client.

require 'net/sftp'
require 'ostruct'
require 'optparse'

class Christina

  Author = "Author => (Nathalon)"
  Script = "Script => (christina.rb)"
  Version = "Version => (0.0.1)"

  def run(arguments)
    parse(arguments)
    connect(arguments)
  end

  private

  def parse(arguments)
    ARGV << "-h" if ARGV.empty?
    @options = OpenStruct.new
    
    args = OptionParser.new do |args|
      args.banner = "Usage: #{__FILE__} [options]"
      
      args.on("-s", "--set-host=HOST", String,
         "The Host To Connect To") do |set_host|
         @options.set_host = set_host
      end
      
      args.on("-u", "--username=USERNAME", String,
         "Authenticate With A Username") do |username|
         @options.username = username
      end

      args.on("-p", "--password=PASSWORD", String,
         "Authenticate With A Password") do |password|
         @options.password = password
      end

      args.on("-w", "--wharf=WHARF", Integer,
         "Specify The Wharf (Port) The Service Is Running") do |wharf|
         @options.wharf = wharf
      end

      args.on("-t", "--transfer=FILE", String,
         "Upload An Entire File On Disk") do |transfer|
         @options.transfer = transfer
      end

      args.on("-d", "--destination=FILE", String,
         "Destination For The Uploaded File") do |destination|
         @options.destination = destination
      end

      args.on("-m", "--mkdir=CREATE DIRECTORY", String,
         "Create A Directory") do |mkdir|
         @options.mkdir = mkdir
      end

      args.on("-r", "--rmdir=REMOVE DIRECTORY", String,
         "Remove A Directory") do |rmdir|
         @options.rmdir = rmdir
      end

      args.on("-q", "--query=FILE", String,
         "Query A File’s Permissions") do |query|
         @options.query = query
      end

      args.on("-e", "--erase=FILE", String,
         "Delete A File") do |erase|
         @options.erase = erase
      end

      args.on("-c", "--change=FILE", String,
         "Change A File’s Permissions") do |change|
         @options.change = change 
      end

      args.on("-a", "--authorization=INTEGER", Integer,
         "Combine With The Above Command To Change A File's Permissions") do |authorization|
         @options.authorization = authorization
      end

      args.on("-b", "--brand=FILE", String,
         "Brand (Rename) A File") do |name|
         @options.name = name
      end

      args.on("-n", "--new=FILE", String,
         "The Name Off The Renamed File") do |new|
         @options.new = new
      end

      args.on("-l", "--list=DIRECTORY", String,
         "Query The Contents Of A Directory") do |list|
         @options.list = list
      end

      args.on("-g", "--grab=FILE", String,
         "Grab Data Off The Remote Host Directly To A Buffer") do |grab|
         @options.grab = grab
      end

      args.on("-f", "--file=FILE", String,
         "Download Directly To A Local File") do |file|
         @options.file = file
      end

      args.on("-o", "--output=FILE", String,
         "Destination Off The Downloaded File") do |output|
         @options.output = output
      end

      args.on("-h", "--help", "Show Help And Exit") do
        puts args
        exit
      end

      args.on("-V", "--version", "Show Version And Exit") do
        puts Author
        puts Script
        puts Version
        exit      
      end

      begin
        args.parse!(arguments)
      
      rescue OptionParser::MissingArgument => error
        puts "[!] => #{error.message}"
        exit

      rescue OptionParser::InvalidOption => error
        puts "[!] => #{error.message}"
        exit
      end
    end
  end

  def connect(arguments)
    output("----------------------------------------------------------")
    output("[*] Starting at => #{Time.now}")
    output("[*] Operating System => #{RUBY_PLATFORM}")
    output("----------------------------------------------------------")

    output("[i] Connecting to Secure SHell")
    output("\t-- Host => #{@options.set_host}")
    output("\t-- Username => #{@options.username}")
    output("\t-- Password => #{@options.password}")
    output("\t-- Wharf => #{@options.wharf}")
    output("----------------------------------------------------------")

    Net::SFTP.start(@options.set_host, @options.username, :password => @options.password, :port => @options.wharf) do |sftp|
      mkdir(sftp) if @options.mkdir
      rmdir(sftp) if @options.rmdir
      remove(sftp) if @options.erase         
      query(sftp) if @options.query
      list(sftp) if @options.list
      grab(sftp) if @options.grab
      rename(sftp) if @options.name || @options.new
      change(sftp) if @options.change || @options.authorization
      upload(sftp) if @options.transfer || @options.destination
      download(sftp) if @options.file || @options.output
    end

    output("----------------------------------------------------------")
    output("[*] Exiting at => #{Time.now}")
    output("----------------------------------------------------------")
  end

  def mkdir(sftp)
    sftp.mkdir!(@options.mkdir)
    output("[i] Creating Directory => #{@options.mkdir}")
  end

  def rmdir(sftp)
    sftp.rmdir!(@options.rmdir)     
    output("[i] Removing Directory => #{@options.rmdir}")
  end

  def remove(sftp)
    sftp.remove!(@options.erase)
    output("[i] Removing File => #{@options.erase}")
  end

  def query(sftp)
    output("[i] Checking Permissions => #{sftp.stat!(@options.query).permissions}")
  end

  def grab(sftp)
    sftp.download!(@options.grab)
    output("[i] Grabing File => #{@options.grab}")
  end

  def rename(sftp)
    sftp.rename!(@options.name, @options.new)
    output("[i] Renaming File => #{@options.name}")
    output("[i] New File => #{@options.new}")
  end

  def change(sftp)
    sftp.setstat!(@options.change, :permissions => @options.authorization)
    output("[i] Setting Permissions To => #{@options.change}")
    output("[i] Permissions Set To => #{@options.authorization}")
  end

  def upload(sftp)  
    sftp.upload!(@options.transfer, @options.destination)
    output("[i] Uploading File To => #{@options.set_host}")
    output("\t-- Local File => #{@options.transfer}")
    output("\t-- File Destination => #{@options.destination}")
  end

  def download(sftp)
    sftp.download!(@options.file, @options.output)
    output("[i] Downloading File From => #{@options.set_host}")
    output("\t-- Remote File => #{@options.file}")
    output("\t-- File Destination => #{@options.output}")
  end

  def list(sftp)
    output("[i] Listing Contents Of => #{@options.list}")
    output("----------------------------------------------------------")
    sftp.dir.foreach(@options.list) do |entry|
    output(entry.longname)
  end
end

  def output(string)
    puts "#{string}"
  end
end

sftp = Christina.new
sftp.run(ARGV)

I'm learning Ruby for three weeks now. This is my Ruby SFTP Client, I managed to write it thanks to spickermann. My question is there any room for improvement? Like incorporating exceptions or something else? Or it is ready to upload it on Github? Thanks in advance. Menu and Methods are working just fine. But to be more exact the whole script is working just fine.