Display an icon only for certain input values in Squib - ruby

My card game (built with Squib) is based on a CSV file. In this file I have (among others) one column called main.
Here's the content of the column... as you see, a lot of nil:
print data['main']
> [3, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0, 0, nil, nil, 0, nil, nil, nil, 0, nil, nil, 0, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 1, nil, nil, nil, nil, nil, -1, nil, nil, nil, nil, 0, 0, 0, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil]
Desired behavior
For each card (row):
If there is a value in this column, I would like to display the value, with a SVG as a background
If there is no value (nil), I would like to skip the text and the svg alltogether
What I tried
1 - I tried the following, but data['sprint'] is an array not a value, so the == does not work:
data = Squib.csv file: 'data.csv'
[...]
if data['Sprint'] != nil
text str: data['Sprint3'], layout: 'sprint3'
svg layout: 'block', file: 'svg\left_block.svg'
end
2 - So I attempted to iterate through the array with an each method, but this of course leads to displaying every element of the array on each card:
data['Main'].each do |n|
if n != nil
text str: n, layout: 'main'
svg layout: 'block', file: 'svg\up_block.svg'
end
end
My Ruby knowledge is here at its end. I have no idea how to display one element only when the value in the main column is not nil. Any idea? Thanks!

Squib's svg works the way you want it to - if it gets nil for file it won't do anything. So in your layout file just put:
block:
file: 'svg\up_block.svg'
And then the svg call does NOT have that "file" option (that sets it for all cards no matter what)
When layout is nil, it'll default to the svg method's "file", which is nil, which happens to do nothing - that's what you want. So then your data field could be something like ['block', nil, nil, nil] and would only show up on the first card.
Check out some new articles I've written on the topic:
http://squib.readthedocs.org/en/latest/arrays.html
http://squib.readthedocs.org/en/latest/guides/getting-started/part_2_iconography.html
(work in progress, of course)
Also, these can also be helpful: https://github.com/andymeneely/squib/blob/master/samples/ranges.rb
That if-statement reminds me how nanDeck would do it - not the same way that Squib works. You COULD do it with an "each", or a "select", but that's more complicated than it needs to be.
(full disclosure: I am the developer of Squib)

Related

Ruby and RSpec - Test fails when expected output is the same as the method

I know I am missing something simple here. I want to write a test that checks if an array of array has been outputted. The test keeps failing but what the test expects is the same that the method is giving.
connect4.rb
class Board
attr_accessor :board
def make_and_print_board
grid = Array.new(6) { Array.new(6)}
p grid
end
end
connect4_spec.rb
require './lib/connect4'
RSpec.describe Board do
let (:new_board) {Board.new}
it "prints board" do
expect{new_board.make_and_print_board}.to output(
Array.new(6) { Array.new(6)}
).to_stdout
end
end
This is the error...
1) Board prints board
Failure/Error:
expect{new_board.make_and_print_board}.to output(
Array.new(6) { Array.new(6)}
).to_stdout
expected block to output [[nil, nil, nil, nil, nil, nil], [nil, nil, nil, nil, nil, nil], [nil, nil, nil, nil, nil, nil], [nil, nil, nil, nil, nil, nil], [nil, nil, nil, nil, nil, nil], [nil, nil, nil, nil, nil, nil]] to stdout, but output "[nil, nil, nil, nil, nil, nil]\n[nil, nil, nil, nil, nil, nil]\n[nil, nil, nil, nil, nil, nil]\n[nil, nil, nil, nil, nil, nil]\n[nil, nil, nil, nil, nil, nil]\n[nil, nil, nil, nil, nil, nil]\n"
What am I missing here? Why isn't it passing? How can I get this test to pass?
The correct way to write this test is to be verbose about your expectation. Test the exact value of what you expect ii to give. p will output a new line so write this way.
RSpec.describe Board do
let (:new_board) {Board.new}
it 'prints board' do
p_output = "[[nil, nil, nil, nil, nil, nil], [nil, nil, nil, nil, nil, nil], [nil, nil, nil, nil, nil, nil], [nil, nil, nil, nil, nil, nil], [nil, nil, nil, nil, nil, nil], [nil, nil, nil, nil, nil, nil]]\n"
expect{new_board.make_and_print_board}.to output(p_output).to_stdout
end
end
But you might want to add this spec if you care more about the internals:
it 'it outputs a 6 x 6 2d array' do
expect( new_board.make_and_print_board ).to match_array Array.new(6) { Array.new(6)}
end

Ruby: For a 2D array,why are nested while loops overwriting elements defined previously? [duplicate]

This question already has answers here:
Creating matrix with `Array.new(n, Array.new)`
(2 answers)
Closed 5 years ago.
Context: Im trying to populate a 2D array with while loops ,after witch I want to try and do it with {} block format. The point is to understand how these two syntax structures can do the same thing.
I have been reviewing this code and scouring the internet for the past hour and Ive decided that I'm simply not getting something, but I dont understand what that is.
The outcome should be
=> [["A1", "A2", "A3", "A4", "A5", "A6", "A7", "A8"]
=> ..(Sequentially)..
=>["H1", "H2", "H3", "H4", "H5", "H6", "H7", "H8"]]
The code is as follows:
char= ('A'..'H').to_a
num= (1..8).to_a
arr=Array.new(8,Array.new(8))
x=0
while x <8
y=0
while y < 8
arr[x][y] = char[x] + num[y].to_s
y+=1
end
x+=1
end
arr
Thank you in advance, I appreciate your patience and time.
####Edit####
The source of the confusion was due to a lack of understanding of the reference concept. Referencing allows us, by using the Array.new(n,Array.new(n)) method scheme, to access the values of the nested arrays that share a reference to their data via their parent array. This question is addressed directly here: Creating matrix with `Array.new(n, Array.new)` . Although I thought it was a issue with my while loops, the problem was indeed how I created the matrix.
Your code is not working due to call to reference. Ruby is pass-by-value, but all the values are references. https://stackoverflow.com/a/1872159/3759158
Have a look at the output
2.4.3 :087 > arr = Array.new(8,Array.new(8))
=> [[nil, nil, nil, nil, nil, nil, nil, nil], [nil, nil, nil, nil, nil, nil, nil, nil], [nil, nil, nil, nil, nil, nil, nil, nil], [nil, nil, nil, nil, nil, nil, nil, nil], [nil, nil, nil, nil, nil, nil, nil, nil], [nil, nil, nil, nil, nil, nil, nil, nil], [nil, nil, nil, nil, nil, nil, nil, nil], [nil, nil, nil, nil, nil, nil, nil, nil]]
2.4.3 :088 > arr[0][0] = 'B'
=> "B"
2.4.3 :089 > arr
=> [["B", nil, nil, nil, nil, nil, nil, nil], ["B", nil, nil, nil, nil, nil, nil, nil], ["B", nil, nil, nil, nil, nil, nil, nil], ["B", nil, nil, nil, nil, nil, nil, nil], ["B", nil, nil, nil, nil, nil, nil, nil], ["B", nil, nil, nil, nil, nil, nil, nil], ["B", nil, nil, nil, nil, nil, nil, nil], ["B", nil, nil, nil, nil, nil, nil, nil]]
This is happen because of call by object on array object you can see this in effect by a simple example
a = []
b = a
b << 10
puts a => [10]
and very same thing is happening with your code.
Instead of all that try this :
('A'..'H').map{|alph| (1..8).map{|num| "#{alph}#{num}"}}

How to download specific links from a page with Nokogiri

I have a webpage with a list of names (which are regular links). When I click on the names of the first page, this opens up another page which has a list of files for download as links. I want to download only the links that end with fq.qz for all of the page1 links.
To do this I have been trying to use Nokogiri:
require 'nokogiri'
require 'open-uri'
url = 'http://myURL/'
doc = Nokogiri::HTML(open(url))
puts doc.css('li')[2]['href']
doc.traverse do |el|
[el[:src], el[:href]].grep(/\.(fq.gz)$/i).map{|l| URI.join(url, l).to_s}.each do |link|
File.open(File.basename(link),'wb'){|f| f << open(link,'rb').read}
end
end
However, I don't think this opens up each of the page 1 links to get the fq.gz ending files in the next level.
The format of the links I am interested in is:
<td>SLX-7998.blabla.fq.gz</td>
I tried using this code which is heavily adapted from one of the answers below but nothing gets downloaded and I get the array as below
master_page.links_with(:href => /ViewSample/).map {|link| link.click
link = agent.get(agent.page.uri.to_s)
if link.content.include?("fq.gz")
out_file = File.new("downloaded_file", "w")
out_file.puts(agent.get_file(link[:href]))
out_file.close
end
=> [nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil]
This is the basis for a quick search for anchors containing certain sub-strings in the linked-text:
require 'nokogiri'
doc = Nokogiri::HTML(<<EOT)
foo.fq.gz
bar.fq.gz
baz
EOT
nodes = doc.search('a').select{ |node| node.text[/fq\.gz$/] }
At this point nodes is a NodeSet of Nodes that match the /fq\.gz$/ pattern in their text:
nodes
# => [#(Element:0x3fd9818bda2c {
# name = "a",
# attributes = [
# #(Attr:0x3fd982027060 { name = "href", value = "http://foo" })],
# children = [ #(Text "foo.fq.gz")]
# }),
# #(Element:0x3fd9818bd928 {
# name = "a",
# attributes = [
# #(Attr:0x3fd982035ef8 { name = "href", value = "http://bar" })],
# children = [ #(Text "bar.fq.gz")]
# })]
We can walk through those and extract just the href parameters:
hrefs = nodes.map{ |node| node['href'] }
Resulting in an array that can be iterated over:
hrefs
# => ["http://foo", "http://bar"]
You should be able to figure out the rest.
You sound like you could use Mechanize, which is a tool for automating interaction with web pages that uses Nokogiri as dependency. You could probably do something like this:
require 'mechanize'
$agent = Mechanize.new
master_page = $agent.get("http://master_page")
master_page.search("a.download_list_link") do |download_list_link|
download_list_page = $agent.get(download_list_link[:href])
download_list_page.search("td > a") do |link|
if link.content.include?("fq.gz")
out_file = File.new("downloaded_file", "w")
out_file.puts($agent.get_file(link[:href]))
out_file.close
end
end
end
Some things that I wrote there will depend on the specific names of elements on the pages you're visiting, but I think that the general idea there will solve your problem.
Edit:
Regarding the errors you're getting with an array of nil objects, one problem that I see is that you forgot to close the block:
master_page.links_with(:href => /ViewSample/).map {|link| link.click
...
# no terminating curly brace

Ruby: printing one attribute of user model for each user

I have a bunch of users in my database with these attributes, however, I only want the email address for each user
#<User id: 1, email: "email#yahoo.com", encrypted_password: "", reset_password_token: nil, reset_password_sent_at: nil, remember_created_at: nil, sign_in_count: 0, current_sign_in_at: nil, last_sign_in_at: nil, current_sign_in_ip: nil, last_sign_in_ip: nil, created_at: "2012-09-03 09:14:01", updated_at: "2012-09-03 09:14:01", name: nil, confirmation_token: nil, confirmed_at: nil, confirmation_sent_at: nil, unconfirmed_email: nil, opt_in: nil, invitation_token: nil, invitation_sent_at: nil, invitation_accepted_at: nil, invitation_limit: nil, invited_by_id: nil, invited_by_type: nil>,
In the console, I did
u = User.all
which printed all the users and their attributes.
Now, to get the email address for each i tried
u.each do |f|
f.email
end
but it just printed the whole list of users again, with all their attributes.
Can anyone show me how to print a list of email addresses for all the users, leaving out the other attributes.
Your console will print at the end the result of what you typed.
So if you write u.each { anything }, the console will print the result of the each loop. To print stuff explicitly, you need to use output function (puts, p, pp, print etc)
users = User.all
puts users.map(&:email).join("\n")

In Ruby, what is good way to filter all the methods of an object that contain the word "time" in it?

I tried the following and it was partly working:
>> s.methods.map {|n| n if n =~ /time/}
=> [nil, nil, nil, nil, nil, nil, nil, nil, "skip_time_zone_conversion_for_attri
butes", nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, ni
l, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, ni
l, "timestamped_migrations", nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, n
il, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, n
il, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, n
il, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, n
il, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, "time_zone_aware
_attributes", nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, n
il, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, "default_timezone", nil, n
il, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, n
il, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, n
il, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, n
il, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, "recor
d_timestamps", nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil,
nil, nil, nil, nil, nil, nil, nil]
>> s.methods.each {|n| p n if n =~ /time/}
"skip_time_zone_conversion_for_attributes"
"timestamped_migrations"
"time_zone_aware_attributes"
"default_timezone"
"record_timestamps"
=> ["extended_by", "before_create", "vote_ids=", "save_without_dirty", "_delete"
, "touch", "daemonize", "after_destroy", "skip_time_zone_conversion_for_attribut
es", "methods", "send", "to_query", "becomes", "after_validation", "store_full_s
ti_class?", "save_with_transactions!", "autosave_associated_records_for_votes",
"require_library_or_gem", "enum_for", "taint", "instance_variable_defined?", "ac
[...] and the rest of the whole array
>> s.methods.filter {|n| n =~ /time/}
NoMethodError: undefined method `filter' for #<Array:0x4de6b00>
from (irb):93
grep is another easy way to accomplish this:
1.9.0 > require 'date'
=> true
1.9.0 > x = Date.new
=> #<Date: -1/2,0,2299161>
1.9.0 > x.methods.grep /time/
=> ["ctime", "asctime", "strftime"]
With the approaches you tried:
map applies the given block to each element of the given enumerable, returning a new enumerable. That's not what you wanted here (as you saw).
methods.each sort of works, but obviously simply printing out the results isn't terribly useful. It wouldn't be Ruby-like at all, but you could have done:
matching_methods = []
s.methods.each {|m| matching_methods << m if m =~ /time/}
to accumulate each method matching /time/ into the matching_methods array. Of course, if you're doing that, then
s.methods.select { |m| m =~ /time/ }
is preferable.
Lastly, filter doesn't exist in Ruby; that's what select (or find_all) is for.
Use Enumerable.select
s.methods.select{|n| n=~/time/}
Or, use grep
s.methods.grep(/time/)
Here's your approach with compact:
s.methods.map{|n| n if n =~ /time/}.compact

Resources