Just started day 2 of migrating from Java to Ruby. My code is quite trivial, I want to print a 9x9 grid but when I go through my nested for loop I can't create a new line termination. Please let me know what I'm missing here, thanks!
table = ""
for i in 1...10 do
for j in 1...10 do
table += j.to_s
end
table += "\n"
end
And, here is the result:
2.1.0 :078 > table
=> "123456789\n123456789\n123456789\n123456789\n123456789\n123456789\n123456789\n123456789\n123456789\n"
You just need to write as puts table. See the method Kernel#puts
table = ""
for i in 1...10 do
for j in 1...10 do
table += j.to_s
end
table += "\n"
end
puts table
# >> 123456789
# >> 123456789
# >> 123456789
# >> 123456789
# >> 123456789
# >> 123456789
# >> 123456789
# >> 123456789
# >> 123456789
A more Ruby way as an example(9X9):
a = Array.new(9,[*1..9]).map(&:join)
puts a
# >> 123456789
# >> 123456789
# >> 123456789
# >> 123456789
# >> 123456789
# >> 123456789
# >> 123456789
# >> 123456789
# >> 123456789
Look the documentation :- Array::new
Behold the magestic power of ruby!!!
puts ([*1..9].join + "\n")*9
Related
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
It's common to need to join strings, and in Ruby we have common ways of doing it: appending, concatenating and interpolating one into the other, or using the built-in concat method in String. (We have multiple ways of doing it for flexibility and to ease the transition from other languages to Ruby.)
Starting with:
'a ' << 'z' # => "a z"
'a '.concat('z') # => "a z"
'a ' + 'z' # => "a z"
"a #{'z'}" # => "a z"
Assuming we don't want to change either string and that the strings won't be assigned to variables, what is the fastest way to join them, and does the fastest way change as the size of the "left" string grows?
For those who can't figure out why we'd post questions like this, it's to help educate and show the most efficient way to do a particular task. Newcomers to a language, Ruby in this case, often drag old ways of doing something with them, and inadvertently write code that runs more slowly than necessary. A simple change to their coding style can result in faster code.
Starting with short strings:
z = 'z'
'a ' << z # => "a z"
'a '.concat(z) # => "a z"
'a ' + z # => "a z"
"a #{z}" # => "a z"
require 'fruity'
compare do
append { 'a ' << z}
concat { 'a '.concat(z)}
plus { 'a ' + z}
interpolate { "a #{z}" }
end
# >> Running each test 65536 times. Test will take about 2 seconds.
# >> interpolate is similar to append
# >> append is similar to plus
# >> plus is faster than concat by 2x ± 0.1
Increasing the "left" string to 11 characters:
require 'fruity'
compare do
append { 'abcdefghij ' << z}
concat { 'abcdefghij '.concat(z)}
plus { 'abcdefghij ' + z}
interpolate { "abcdefghij #{z}" }
end
# >> Running each test 65536 times. Test will take about 2 seconds.
# >> interpolate is similar to append
# >> append is similar to plus
# >> plus is faster than concat by 2x ± 1.0
51 characters:
compare do
append { 'abcdefghijabcdefghijabcdefghijabcdefghijabcdefghij ' << z}
concat { 'abcdefghijabcdefghijabcdefghijabcdefghijabcdefghij '.concat(z)}
plus { 'abcdefghijabcdefghijabcdefghijabcdefghijabcdefghij ' + z}
interpolate { "abcdefghijabcdefghijabcdefghijabcdefghijabcdefghij #{z}" }
end
# >> Running each test 32768 times. Test will take about 2 seconds.
# >> plus is faster than append by 2x ± 1.0
# >> append is similar to interpolate
# >> interpolate is similar to concat
101:
compare do
append { 'abcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghij ' << z}
concat { 'abcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghij '.concat(z)}
plus { 'abcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghij ' + z}
interpolate { "abcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghij #{z}" }
end
# >> Running each test 32768 times. Test will take about 2 seconds.
# >> plus is faster than interpolate by 2x ± 0.1
# >> interpolate is similar to append
# >> append is similar to concat
501:
compare do
append { 'abcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghij ' << z}
concat { 'abcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghij '.concat(z)}
plus { 'abcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghij ' + z}
interpolate { "abcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghij #{z}" }
end
# >> Running each test 16384 times. Test will take about 1 second.
# >> plus is faster than append by 2x ± 0.1
# >> append is similar to interpolate
# >> interpolate is similar to concat
Once the strings got past 50 characters + consistently outperformed the others.
In the comments there are mention of some of these mutating the string on the left. Here's what would happen if it was a variable on the left, not a literal string:
a = 'a'
z = 'z'
a << z # => "az"
a # => "az"
a = 'a'
a.concat(z) # => "az"
a # => "az"
compared to:
a + z # => "az"
a # => "a"
"#{a} #{z}" # => "a z"
a # => "a"
Note: The initial version of answer had a bad test using:
"a #{'z'}"
The problem with that is Ruby is smart enough to recognize that 'z' is another literal and converts the string into:
"a z"
with the end result that the test would be unfairly faster than the others.
It's been a while and Ruby's smarter and faster. I added a couple additional tests:
puts "Running Ruby v%s" % RUBY_VERSION
require 'fruity'
z_ = 'z'
compare do
append { 'abcdefghij ' << 'z' }
concat { 'abcdefghij '.concat('z') }
plus { 'abcdefghij ' + 'z' }
interpolate1 { "abcdefghij #{'z'}" }
interpolate2 { "abcdefghij #{z_}" }
adjacent { 'abcdefghij' ' z' }
end
# >> Running Ruby v2.7.0
# >> Running each test 65536 times. Test will take about 3 seconds.
# >> adjacent is similar to interpolate1
# >> interpolate1 is faster than interpolate2 by 2x ± 1.0
# >> interpolate2 is similar to append
# >> append is similar to concat
# >> concat is similar to plus
interpolate1 and adjacent are basically the same as far as the interpreter is concerned and will be concatenated prior to running. interpolate2 forces Ruby to do it at run-time so it's a little slower.
I have a YAML file that is going to be parsed by two different machines, so I want to specify some sort of markers in the file to indicate which machine has the right to read a specific block.
As an example I want the block 1 to be parsed by machine 1 and block 2 to be parsed by machine2:
# BLOCK 1 - Machine 1
-
:id: 1234
:worker: Foo1
:opts:
:ftpaccount: user1
:limit: 10
# BLOCK 2 - Machine 2
-
:id: 5678
:worker: Foo2
:opts:
:ftpaccount: user2
:limit: 10
How can I achieve something like this? How you implement something similar to this? Thanks.
Treat the blocks as hash entries with the key being the hostname:
require 'yaml'
yaml = <<EOT
host1:
# BLOCK 1 - Machine 1
-
:id: 1234
:worker: Foo1
:opts:
:ftpaccount: user1
:limit: 10
host2:
# BLOCK 2 - Machine 2
-
:id: 5678
:worker: Foo2
:opts:
:ftpaccount: user2
:limit: 10
EOT
config = YAML.load(yaml)
# => {"host1"=>
# [{:id=>1234,
# :worker=>"Foo1",
# :opts=>{:ftpaccount=>"user1", :limit=>10}}],
# "host2"=>
# [{:id=>5678,
# :worker=>"Foo2",
# :opts=>{:ftpaccount=>"user2", :limit=>10}}]}
At this point you can grab the chunk you need:
config['host1']
# => [{:id=>1234, :worker=>"Foo1", :opts=>{:ftpaccount=>"user1", :limit=>10}}]
config['host2']
# => [{:id=>5678, :worker=>"Foo2", :opts=>{:ftpaccount=>"user2", :limit=>10}}]
You don't even have to hard-code the hostname; You can ask the machine what its name is:
`hostname`.chomp # => "MyHost"
Actually, I'd change the YAML a little, so it's a hash of hashes. As is, your YAML returns a hash of arrays of hashes, which, because of the array, makes it more awkward to use:
host1:
# BLOCK 1 - Machine 1
:id: 1234
:worker: Foo1
:opts:
:ftpaccount: user1
:limit: 10
host2:
# BLOCK 2 - Machine 2
:id: 5678
:worker: Foo2
:opts:
:ftpaccount: user2
:limit: 10
Results in:
config = YAML.load(yaml)
# => {"host1"=>
# {:id=>1234, :worker=>"Foo1", :opts=>{:ftpaccount=>"user1", :limit=>10}},
# "host2"=>
# {:id=>5678, :worker=>"Foo2", :opts=>{:ftpaccount=>"user2", :limit=>10}}}
config['host1']
# => {:id=>1234, :worker=>"Foo1", :opts=>{:ftpaccount=>"user1", :limit=>10}}
config['host2']
# => {:id=>5678, :worker=>"Foo2", :opts=>{:ftpaccount=>"user2", :limit=>10}}
Finally, if your YAML file is complex, or long, or has repeated sections, seriously consider writing code that emits that file for you. Ruby makes it really easy to generate the YAML in a very smart way that automatically uses aliases. For instance:
require 'yaml'
SOME_COMMON_DATA = {
'shared_db_dsn' => 'mysql://user:password#host/db'
}
HOST1 = 'foo.com'
HOST1_DATA = {
HOST1 => {
'id' => 1234,
'worker' => 'Foo1',
'opts' => {
'ftpaccount' => 'user1',
'limit' => 10
},
'dsn' => SOME_COMMON_DATA
}
}
HOST2 = 'bar.com'
HOST2_DATA = {
HOST2 => {
'id' => 5678,
'worker' => 'Foo2',
'opts' => {
'ftpaccount' => 'user2',
'limit' => 10
},
'dsn' => SOME_COMMON_DATA
}
}
data = {
HOST1 => HOST1_DATA,
HOST2 => HOST2_DATA,
}
puts data.to_yaml
# >> ---
# >> foo.com:
# >> foo.com:
# >> id: 1234
# >> worker: Foo1
# >> opts:
# >> ftpaccount: user1
# >> limit: 10
# >> dsn: &1
# >> shared_db_dsn: mysql://user:password#host/db
# >> bar.com:
# >> bar.com:
# >> id: 5678
# >> worker: Foo2
# >> opts:
# >> ftpaccount: user2
# >> limit: 10
# >> dsn: *1
Notice how YAML converted "dsn" into an alias and referenced it in the second host's definition using an anchor. This can add up to serious space savings, depending on how you define your variables and build the data structure. See "Aliases and Anchors" for more information.
Also, I'd highly recommend avoiding the use of symbols for your hash keys. By doing so your YAML can be easily loaded by other languages, not just Ruby. At that point, your YAML becomes even more useful when building big systems.
Here's a simple state machine that assembles a string based on the most recent matching comment in the yaml file. The YAML string is then loaded into the parser. If your files are really large, you could easily modify this to use Tempfile or some other IO class.
require 'yaml'
class YAMLSplitter
attr_reader :flag, :mode, :raw
def initialize(flag)
#flag = flag
#mode = :match
#raw = ""
end
def parse(file)
File.read(file).each_line do |line|
process_line(line)
end
YAML.load(raw)
end
private
def process_line(line)
set_match_status(line)
write_line(line) if match?
end
def set_match_status(line)
if line.start_with?("#")
if line.match(flag)
match!
else
nomatch!
end
end
end
def write_line(line)
puts "WRITE_LINE #{mode.inspect} #{line.inspect}"
raw << line
end
def match?
mode == :match
end
def match!
#mode = :match
end
def nomatch!
#mode = :nomatch
end
end
YAML:
---
# machine 1
- 1
- 2
- 3
- 4
# machine 2
- 5
- 6
- 7
- 8
- 9
- 10
- 11
# machine 1
- 12
Execution:
splitter = YAMLSplitter.new('machine 1')
yaml = splitter.parse('test.yml')
I want to get date range between from and till in Rails seed.
When I try to generate date range ((Date.today - 10)..Date.today) exception occurred.
Exception message: bad value for range
But in the Rails Console everything all right.
I think ActiveSupport are reasonable for that (my debugger told me that).
Ralls 3.1.3
What's going on?
You can understand what's going on by splitting the two edges and check their class like so:
Date.today.class # => Date
(Date.today - 10).class # => Date
((Date.today - 10)..Date.today).each {|d| puts d.class} # => 10 Date works for me
The error you're experiencing is something like this:
('a'..10) # => ArgumentError: bad value for range
Can you post the classes of your 2 edges of the range?
(Date.today - 10).class => ?
Date.today.class => ?
Have you overwritten any class in your rails environment? Does it work in irb?
PS: As you're in rails you can use 10.days.ago but you'll need to use to_date as it's a ActiveSupport::TimeWithZone
begin
((Date.today - 10)..Date.today).each { |date| puts date }
rescue
$! # => #<NameError: uninitialized constant Date>
end
require 'date'
((Date.today - 10)..Date.today).each { |date| puts date }
# >> 2012-04-06
# >> 2012-04-07
# >> 2012-04-08
# >> 2012-04-09
# >> 2012-04-10
# >> 2012-04-11
# >> 2012-04-12
# >> 2012-04-13
# >> 2012-04-14
# >> 2012-04-15
# >> 2012-04-16
Hey guys,
i have 5 model attributes, for example, 'str' and 'dex'. A user has strength, dexterity attribute.
When i call user.increase_attr('dex') i want to do it through 'dex' and not having to pass 'dexterity' string all the way.
Of course, i can just check if ability == 'dex' and convert it to 'dexterity' when i will need to do user.dexterity += 1 and then save it.
But what is a good ruby way to do that ?
Look at Ruby's Abbrev module that's part of the standard library. This should give you some ideas.
require 'abbrev'
require 'pp'
class User
def increase_attr(s)
"increasing using '#{s}'"
end
end
abbreviations = Hash[*Abbrev::abbrev(%w[dexterity strength speed height weight]).flatten]
user = User.new
user.increase_attr(abbreviations['dex']) # => "increasing using 'dexterity'"
user.increase_attr(abbreviations['s']) # => "increasing using ''"
user.increase_attr(abbreviations['st']) # => "increasing using 'strength'"
user.increase_attr(abbreviations['sp']) # => "increasing using 'speed'"
If an ambiguous value is passed in, (the "s"), nothing will match. If a unique value is found in the hash, the returned value is the full string, making it easy to map short strings to the full string.
Because having varying lengths of the trigger strings would be confusing to the user you could strip all elements of the hash that have keys shorter than the shortest unambiguous key. In other words, remove anything shorter than two characters because of the collision of "speed" ("sp") and "strength" ("st"), meaning "h", "d" and "w" need to go. It's a "be kind to the poor human users" thing.
Here's what is created when Abbrev::abbrev does its magic and it's coerced into a Hash.
pp abbreviations
# >> {"dexterit"=>"dexterity",
# >> "dexteri"=>"dexterity",
# >> "dexter"=>"dexterity",
# >> "dexte"=>"dexterity",
# >> "dext"=>"dexterity",
# >> "dex"=>"dexterity",
# >> "de"=>"dexterity",
# >> "d"=>"dexterity",
# >> "strengt"=>"strength",
# >> "streng"=>"strength",
# >> "stren"=>"strength",
# >> "stre"=>"strength",
# >> "str"=>"strength",
# >> "st"=>"strength",
# >> "spee"=>"speed",
# >> "spe"=>"speed",
# >> "sp"=>"speed",
# >> "heigh"=>"height",
# >> "heig"=>"height",
# >> "hei"=>"height",
# >> "he"=>"height",
# >> "h"=>"height",
# >> "weigh"=>"weight",
# >> "weig"=>"weight",
# >> "wei"=>"weight",
# >> "we"=>"weight",
# >> "w"=>"weight",
# >> "dexterity"=>"dexterity",
# >> "strength"=>"strength",
# >> "speed"=>"speed",
# >> "height"=>"height",
# >> "weight"=>"weight"}
def increase_attr(attr)
attr_map = {'dex' => :dexterity, 'str' => :strength}
increment!(attr_map[attr]) if attr_map.include?(attr)
end
Basically create a Hash that has the key of 'dex', 'str' etc and points to the expanded version of that word(in symbol format).