undefined method `include?' for nil:NilClass (NoMethodError) - ruby-on-rails

I have the following code, and am using the ARGV. And I would make it so that when the user left the null ARGV, show some message.
=begin
TLDentifier developed by Arsh Leak. 2014.
Commands:
--display : Show all TLDs registered.
--help : Show more informations.
target.com
=end
class String
def green; "\033[32m#{self}\033[0m" end
def blue; "\033[34m#{self}\033[0m" end
def cyan; "\033[36m#{self}\033[0m" end
def bold; "\033[1m#{self}\033[22m" end
end
system("clear")
domains = {
".br" => "Brazilian",
".com" => "Comercial",
".aero" => "Aircraft",
".biz" => "Business",
".coop" => "Cooperative",
".edu" => "Educational",
".gov" => "Government",
".info" => "Information",
".int" => "International organization",
}
def head()
"TLDentifier".green.bold
end
puts head()
name = ARGV.first
puts "[#{name}]".blue.bold
domains.each do |domain, etn|
if name.include? (domain)
puts "["+domain.cyan+"] is a "+etn+" Domain."
elsif name == "--help"
system("clear")
puts head()
puts ""
puts "Development.".cyan
puts "Developed by "+"Arsh Leak. 2014."
puts ""
puts ""
puts "GitHub.".cyan
puts "github.com/4rsh"
puts ""
puts "Facebook.".cyan
puts "facebook.com/doxnetwork"
puts ""
puts "Blog.".cyan
puts "doxnetwork.com/"
puts ""
puts "Credits.".cyan
puts "Prof. Eric Weinstein."
puts ""
puts "How to.".cyan
puts "If you want to identify all TLDs, type:"
puts "$ ruby ltdentifier.rb --display".green
puts ""
puts "If you want to identify a specific TLD, type:"
puts "$ ruby ltdentifier.rb www.website.com/dir or www.website.com.".green
puts ""
elsif name == "--display"
head()
puts "Domain:".green+domain+" -"+" Entity: ".green+etn
end
end
And, the script return this error:
tld.rb:302:in block in <main>': undefined methodinclude?' for nil:NilClass (NoMethodError)
from tld.rb:301:in each'
from tld.rb:301:in'

When no arguments are passed, ARGV.first returns nil, which is not a String and thus doesn't respond to include?. nil acts like false, so you can test for this by putting code like
unless name
puts "Need at least one argument"
exit
end
before your first use of name.

Related

Pass Params from select_tag in rails to one script.rb get this params

Hello how is it possible to pass web parameters to an rb script in rails?
I'm using select_tag where when choosing an option I send the value to a variable in script.rb
Could help me I'm studying ruby ​​and rails is very complicated for me to do this.
my controller.rb
#myvalue = ["OPT VALUE 1","OPT VALUE 2"]
my external script.rb
loop do
#give_my_param_from_rails = gets.chomp
case #give_my_param_from_rails
when '1'
puts "i get number 1"
when '2'
puts "i get number 2"
else
puts "dont get any value"
break
end
end
my html.erb
<%= select_tag "my_options", options_for_select(#myvalue) %>
In my external script I want the rails value selected in select_tag to be set in the #give_my_param_from_rails variable help me?
I've added $stdout.flush to the end of your script to flush the output for each line of input:
loop do
line = gets.chomp
case line
when '1'
puts "i get number 1"
when '2'
puts "i get number 2"
else
puts "dont get any value"
break
end
$stdout.flush # flush output after each line of input
end
To access the script in your controller you can now do:
# allow writing to io by using r+ mode
# https://ruby-doc.org/core-2.6.5/IO.html#method-c-new-label-IO+Open+Mode
File.popen('ruby /path/to/script.rb', 'r+') do |io|
io.puts params[:my_options] # assuming params[:my_options] is "1"
io.gets #=> "i get number 1\n"
io.puts 2
io.gets #=> "i get number 2\n"
io.puts "foo bar" # falling in the else scenario breaks the loop, exiting the script
io.gets #=> "dont get any value\n"
io.puts 1
io.gets #=> nil
io.puts "foo bar"
io.gets #=> nil
end
If you only need to supply one input you could use backticks instead:
input = params[:my_options] # assuming params[:my_options] is "foo bar"
# escape special characters in double quoted context
# https://www.gnu.org/software/bash/manual/html_node/Double-Quotes.html
sanatized_input = input.gsub(/([$`\\"])/, '\\\\\1')
output = `echo "${sanatized_input}" | ruby /path/to/script.rb`
#=> "dont get any value\n"
Keep in mind that you don't handle the scenario where you supply 1 or 2 and then close the input. When this happens the next gets call will return nil.
`echo 1 | ruby /path/to/script.rb`
# script.rb:2:in `block in <main>': undefined method `chomp' for nil:NilClass (NoMethodError)
# from script.rb:1:in `loop'
# from script.rb:1:in `<main>'
#=> "i get number 1\n"
To resolve this you could do something like:
loop do
line = gets or break # break the loop if gets returns nil
line.chomp!
# ...
end

How to list all available locale keys in Rails?

My locale file has become unwieldy with a bunch of nested keys. Is there a way to get a list of all available locale keys, or all locale keys from a single locale file?
For eg.
en:
car:
honda:
civic:
name: 'Civic'
description: 'Entry Level Sedan'
ferrari:
la_ferrari:
name: 'La Ferrari'
description: 'Supercar'
This locale should return the list of keys, which in this case is
['en.car.honda.civic.name', 'en.car.honda.civic.description',
'en.ferrari.la_ferrari.name', 'en.car.ferrari.la_ferrari.name.description']
Is there a Rails (I18n) helper to do this?
The other way is to iterate over the parsed YAML.
To get an array of available locales:
I18n.available_locales
I recommend avoiding putting multiple locales in one YAML file. If you need to do so for some processing-related reason, you can always concatenate the files on the fly with, e.g., your *NIX shell:
...to a file
cat my_app/config/locales/*.yml >> locales.yml
...or to another processs
cat my_app/config/locales/*.yml | command_that_takes_stdin -
This is a script I've written when I had to deal with this. Working great for me.
#! /usr/bin/env ruby
require 'yaml'
filename = if ARGV.length == 1
ARGV[0]
elsif ARGV.length == 0
"/path/to/project/config/locales/new.yml"
end
unless filename
puts "Usage: flat_print.rb filename"
exit(1)
end
hash = YAML.load_file(filename)
hash = hash[hash.keys.first]
def recurse(obj, current_path = [], &block)
if obj.is_a?(String)
path = current_path.join('.')
yield [path, obj]
elsif obj.is_a?(Hash)
obj.each do |k, v|
recurse(v, current_path + [k], &block)
end
end
end
recurse(hash) do |path, value|
puts path
end
I do not pretend that this is a uniqe right solution, but this code works for me.
# config/initializers/i18n.rb
module I18n
class << self
def get_keys(hsh = nil, parent = nil, ary = [])
hsh = YAML.load_file("config/locales/en.yml") unless hsh
keys = hsh.keys
keys.each do |key|
if hsh.fetch(key).is_a?(Hash)
get_keys(hsh.fetch(key), "#{parent}.#{key}", ary)
else
keys.each do |another|
ary << "#{parent}.#{another}"[1..-1]
end
end
end
ary.uniq
end
end
end
Result
[14] pry(main)> I18n.get_keys
=> ["en.car.honda.civic.name", "en.car.honda.civic.description", "en.car.ferrari.la_ferrari.name", "en.car.ferrari.la_ferrari.description", "en.car.suzuki.escudo.name", "en.car.suzuki.escudo.description"]
My en.yml
en:
car:
honda:
civic:
name: 'Civic'
description: 'Entry Level Sedan'
ferrari:
la_ferrari:
name: 'La Ferrari'
description: 'Supercar'
suzuki:
escudo:
name: 'Escudo'
description: 'SUV'

How to check if a variable exists with a value without "undefined local variable or method"?

This is a common pattern: If a variable doesn't exist I get an undefined local variable or method error.
The existing code has if variable_name.present? but this didn't account for the variable not existing.
How can I check the value of the variable and also account for it not existing at all?
I've tried:
if (defined? mmm) then
if mmm.present? then
puts "true"
end
end
but Ruby still checks that inner mmm.present? and throws "no such variable" when it doesn't exist.
I'm sure there's a common pattern/solution to this.
Change the present? to != '' and use the && operator which only tries to evaluate the seond expression if the first one is true:
if defined?(mmm) && (mmm != '') then puts "yes" end
But actually as of 2019 this is no longer needed as both the below work
irb(main):001:0> if (defined? mm) then
irb(main):002:1* if mm.present? then
irb(main):003:2* p true
irb(main):004:2> end
irb(main):005:1> end
=> nil
irb(main):006:0> if (defined? mm) then
irb(main):007:1* p mm
irb(main):008:1> end
=> nil
On Ruby on Rails
if defined?(mm) && mm.present?
puts "acceptable variable"
end
On IRB
if defined?(mm) && !mm.blank? && !mm.nil?
puts "acceptable variable"
end
It can make sure you won't get undefined variable or nil or empty value.
Understand how defined? works
a = 1
defined?(a) # => "local-variable"
b = nil
defined?(b) # => "local-variable"
c = ""
defined?(c) # => "local-variable"
d = []
defined?(d) # => "local-variable"
$e = 'text'
defined?($e) # => "global-variable"
defined?(f) # => nil
defined?($g) # => nil
Note that defined? checks variable in the scope it is.
Why you need defined?
When there is possible of undefined variable presence, you cannot just check it with only .nil? for eaxample, you will have a chance to get NameError.
a = nil
a.nil? # => true
b.nil? # => NameError: undefined local variable or method `b'

I18n: How to check if a translation key/value pairs is missing?

I am using Ruby on Rails 3.1.0 and the I18n gem. I (am implementing a plugin and) I would like to check at runtime if the I18n is missing a translation key/value pairs and, if so, to use a custom string. That is, I have:
validates :link_url,
:format => {
:with => REGEX,
:message => I18n.t(
'custom_invalid_format',
:scope => 'activerecord.errors.messages'
)
}
If in the .yml file there is not the following code
activerecord:
errors:
messages:
custom_invalid_format: This is the test error message 1
I would like to use the This is the test error message 2. Is it possible? If so, how can I make that?
BTW: For performance reasons, is it advisable to check at runtime if the translation key/value pairs is present?
You could pass a :default parameter to I18n.t:
I18n.t :missing, :default => 'Not here'
# => 'Not here'
You can read more about it here.
I just had the same question and I want to compute an automatic string in case the translation is missing. If I use the :default option I have to compute the automatic string every time even when the translation is not missing. So I searched for another solution.
You can add the option :raise => true or use I18n.translate! instead of I18n.translate. If no translation can be found an exception is raised.
begin
I18n.translate!('this.key.should.be.translated', :raise => true)
rescue I18n::MissingTranslationData
do_some_resource_eating_text_generation_here
end
I don't know how to this at runtime but you can use rake to find it out. You'll have create your own rake task for that. Here's one:
namespace :i18n do
desc "Find and list translation keys that do not exist in all locales"
task :missing_keys => :environment do
def collect_keys(scope, translations)
full_keys = []
translations.to_a.each do |key, translations|
new_scope = scope.dup << key
if translations.is_a?(Hash)
full_keys += collect_keys(new_scope, translations)
else
full_keys << new_scope.join('.')
end
end
return full_keys
end
# Make sure we've loaded the translations
I18n.backend.send(:init_translations)
puts "#{I18n.available_locales.size} #{I18n.available_locales.size == 1 ? 'locale' : 'locales'} available: #{I18n.available_locales.to_sentence}"
# Get all keys from all locales
all_keys = I18n.backend.send(:translations).collect do |check_locale, translations|
collect_keys([], translations).sort
end.flatten.uniq
puts "#{all_keys.size} #{all_keys.size == 1 ? 'unique key' : 'unique keys'} found."
missing_keys = {}
all_keys.each do |key|
I18n.available_locales.each do |locale|
I18n.locale = locale
begin
result = I18n.translate(key, :raise => true)
rescue I18n::MissingInterpolationArgument
# noop
rescue I18n::MissingTranslationData
if missing_keys[key]
missing_keys[key] << locale
else
missing_keys[key] = [locale]
end
end
end
end
puts "#{missing_keys.size} #{missing_keys.size == 1 ? 'key is missing' : 'keys are missing'} from one or more locales:"
missing_keys.keys.sort.each do |key|
puts "'#{key}': Missing from #{missing_keys[key].join(', ')}"
end
end
end
put the given in a .rake file in your lib/tasks directory and execute:
rake i18n:missing_keys
Information source is here and code on github here.
If you wish to pass variable to the message like This is the test error message {variable}
This is possible using variable in language file like below.
# app/views/home/index.html.erb
<%=t 'greet_username', :user => "Bill", :message => "Goodbye" %>
# config/locales/en.yml
en:
greet_username: "%{message}, %{user}!"
More description you can find here.

How to make Rails add line numbers / time stamps to log messages?

I use tail -f to display the log file when developing my Rails app.
It shows the log messages (in color! :), which is great.
But with so much information in the 80-width console, it becomes difficult to track where a certain "set" of log messages started when, say, I clicked on a button to GET a resource.
It would be easier if there was a line number or even a time stamp at the start of each log message/line. This way I could remember that I need to start looking at the log "after line number 2365" or "after 2010/10/10 23:33:23:45".
Is this possible to do? Is there some Rails internal option for this ?
why don't you just edit your desired environment's log tags
development.rb
config.log_tags [ lambda {|r| DateTime.now } ]
If you wanted to get a time stamp:
class ApplicationController < ActionController::Base
# ...
before_filter :log_tracker
def log_tracker
Rails.logger.add(1, "Log Date: #{DateTime.now}")
end
end
And format the date however you see fit....
That would work for Rails 2.1 +, prior you could access the ActiveSupport::Buffered log object with the constant: RAILS_DEFAULT_LOGGER
Get access to the actual log file with Rails.logger.instance_values["log"]
Getting the number of lines is difficult because the logger only opens the file for writing, probably for economy. I get an IOError: not opened for reading when I try.
`
Thanks #scaney.
I found a solution here.
I modified that code to add my own coloring highlights (for development only of course!) and now I can see things like 'parameters' in yellow in the console and I'm very pleased now!
In case someone is interested, here is the code I put at the end of environment.rb.
Here is my current (dirty) implementation. Will probably fix this up later (maybe make a gem, but for now this serves me fine)
WARNING
DIRTY CODE FOLLOWS! Use at your own risk!
module ActiveSupport
class BufferedLogger
#define the ANSI escape codes for normal and bright colors
$my_my_ansi_colors = {
:normal => "\x1B[0m",
:black => "\x1B[30m",
:red => "\x1B[31m", #red
:green => "\x1B[32m",
:yellow => "\x1B[33m",
:blue => "\x1B[34m",
:magenta => "\x1B[35m",
:cyan => "\x1B[36m",
:white => "\x1B[37m",
:bred => "\x1B[1m\x1B[31m", #bright red
:bgreen => "\x1B[1m\x1B[32m",
:byellow => "\x1B[1m\x1B[33m",
:bblue => "\x1B[1m\x1B[34m",
:bmagenta => "\x1B[1m\x1B[35m",
:bcyan => "\x1B[1m\x1B[36m",
:bwhite => "\x1B[1m\x1B[37m",
}
#take a string and using the keys in the hash, replace the keys in the
#string but surround the keys with ANSI color codes
#No idea how to retain the case of the key!(TODO someday)
def my_highlight msgx,hash
return msgx if msgx.blank?
return msgx if hash.empty?
hash.each_pair do |k,v|
if not k.nil?
msgx.gsub! Regexp.new(k, Regexp::IGNORECASE), $my_my_ansi_colors[:normal]+$my_my_ansi_colors[v]+k.upcase+$my_my_ansi_colors[:normal]
end
end
msgx
end
def add(severity, message = nil, progname = nil, &block)
return if #level > severity
message = (message || (block && block.call) || progname).to_s
#INSERT BEGINS
if not $myownglobalnumbercounter.nil?
$myownglobalnumbercounter += 1
else
$myownglobalnumbercounter = 1
end
level = {
0 => "DEBUG",
1 => "INFO",
2 => "WARN",
3 => "ERROR",
4 => "FATAL"
}[severity] || "U"
message = "\x1B[0m[%d %s] : %s" % [$myownglobalnumbercounter,level,message]
message = my_highlight message, {
"debug" => :white,
"error" => :bred,
"info" => :bwhite,
"warning" => :byellow,
"warn" => :byellow ,
"parameters" => :byellow,
"#" => :bgreen,
"ms " => :bmagenta,
"GET " => :bmagenta,
"PUT " => :bmagenta,
"POST " => :bmagenta,
"DELETE " => :bmagenta
}
#INSERT ENDS
message = "#{message}\n" unless message[-1] == ?\n
buffer << message
auto_flush
message
end
end
end

Resources