modify active record relation in ruby - ruby

I have my #albums which are working fine; pickung data up with albums.json.
What I'd like to do is to split this #albums in three parts.
I was thinking of something like { "ownAlbums" : [ ... ], "friendSubscriptions" : [ ... ], "otherSubscriptions" : [ ... ] } But I got several errors like
syntax error, unexpected tASSOC, expecting kEND #albums["own"] => #albums
when I tried
#albums["own"] => #albums
or
TypeError (Symbol as array index):
when I tried:
#albums[:otherSubscriptions] = 'others'
and so on.
I never tried something like this before but this .json is just a simple array ?
How can I split it in three parts ?
Or do I have to modify the active record to do so ? Because if so, I'd find another way than splitting.
Second Edit
I tried something like this and it's actually working:
#albums = [*#albums]
own = []
cnt = 0
#albums.each do |ownAlbum|
cnt = cnt.to_int
own[cnt] = ownAlbum
cnt=cnt+1
end
subs = Subscription.where(:user_id => #user.user_id)
#albums[0] = own
#albums[1] = subs
But where I have [0] and [1] I'D prefer Strings.
But then I get the error: TypeError (can't convert String into Integer):
How to get around that ?

Related

Convert and translate a Ruby hash into a human-readable string

I have the following Ruby hash:
{"limit"=>250, "days_ago"=>14, "days_ago_filter"=>"lt", "key"=>3}
I'd like to convert it to a human-readable string and translate some of the values as necessary:
Limit: 250 - Days Ago: 14 - Days Ago Filter: Less than - Key: D♯, E♭,
So lt, in this case, actually translates to Less than. and 3 for key translates to D♯, E♭.
I'm almost there with this:
variables.map {|k,v| "#{k.split('_').map(&:capitalize).join(' ')}: #{v}"}.join(' - ')
But translating those values is where I'm hitting a snag.
I'd suggest using hashes for mapping out the possible values, e.g.:
days_ago_filter_map = {
"lt" => "Less than",
# ...other cases here...
}
musical_key_map = {
3 => "D♯, E♭",
# ...other cases here...
}
Then you can switch on the key:
variables.map do |key, value|
label = "#{key.split('_').map(&:capitalize).join(' ')}"
formatted_value = case key
when "days_ago_filter" then days_ago_filter_map.fetch(value)
when "key" then musical_key_map.fetch(value)
else value
end
"#{label}: #{formatted_value}"
end.join(' - ')
Note that if you're missing anything in your maps, the above code will raise KeyNotFound errors. You can set a default in your fetch, e.g.
days_ago_filter_map.fetch(value, "Unknown filter")
musical_key_map.fetch(value, "No notes found for that key")
You can create YAML files too for such kind of mappings :
values_for_replacement = {
"lt" => "Less than",
3 => "D♯, E♭"
}
you can try following :
variables.map {|k,v|
value_to_be_replaced = values_for_replacement[v]
"#{k.humanize}: #{(value_to_be_replaced.present? ? value_to_be_replaced : v)}"}.join(' - ')

how to amend a code to get query from external and save result to external

I have a code which looks like this
require 'net/http'
base = 'www.uniprot.org'
tool = 'mapping'
params = {
'from' => 'ACC+ID', 'to' => 'P_ENTREZGENEID', 'format' => 'tab',
'query' => 'A0A0K3AVS5 A0A0K3AVV4 A0A0K3AW32 A0A0K3AWP0'
}
http = Net::HTTP.new base
$stderr.puts "Submitting...\n";
response = http.request_post '/' + tool + '/',
params.keys.map {|key| key + '=' + params[key]}.join('&')
loc = nil
while response.code == '302'
loc = response['Location']
response = http.request_get loc
end
while loc
wait = response['Retry-After'] or break
$stderr.puts "Waiting (#{wait})...\n";
sleep wait.to_i
response = http.request_get loc
end
response.value # raises http error if not 2xx
puts response.body
which gives me what I need. however, I have two questions
1- How to load a query list instead I parse it into the code ? lets say I save a txt file with all the query i want to the desktop of a mac
2- How to export the output ?
If I have
B2D6P1
G5EC52
B2FDA8-2
B2MZB1
B3CJ34
B3CKG1
B3GWA1
what #tadman showed gives me the answer
however, I have the following
B2D6P1
G5EC52;B2D6P4
B2FDA8-2;B2FDA8
B2MZB1;P18834
B3CJ34
B3CKG1
B3GWA1;Q8I7K5
and the answer is like below
B2D6P1 rmd-2
G5EC52 tlf-1
B2D6P4 tlf-1
B2FDA8 smc-3
B2MZB1 col-14
P18834 col-14
B3CJ34 gcn-1
B3CKG1 urm-1
B3GWA1 nono-1
Q8I7K5 nono-1
what I want is that if I have two entries in each row (separated with ;) leading to the similar output , it gives me only one , otherwise give me as many as they have for example in above example , my desire output is
B2D6P1 rmd-2
G5EC52;B2D6P4 tlf-1
B2FDA8-2;B2FDA8 smc-3
B2MZB1;P18834 col-14
B3CJ34 gcn-1
B3CKG1 urm-1
B3GWA1;Q8I7K5 nono-1
is this possible ?
Reading query data:
query = File.readlines('ids.txt').map(&:chomp).join(' ')
That way you can have them on separate lines, easier to edit, and they're space separated when submitted.
That makes your params look like:
params = {
'query' => query,
...
}
Writing data:
File.open('output.txt', 'w') do |f|
f.write(response.body)
end
That's all there is to it. If it's a string, or can be converted to a string, you can write it to a file.

Parsing a string field

I have these Syslog messages:
N 4000000 PROD 15307 23:58:12.13 JOB78035 00000000 $HASP395 GGIVJS27 ENDED\r
NI0000000 PROD 15307 23:58:13.41 STC81508 00000200 $A J78036 /* CA-JOBTRAC JOB RELEASE */\r
I would like to parse these messages into various fields in a Hash, e.g.:
event['recordtype'] #=> "N"
event['routingcode'] #=> "4000000"
event['systemname'] #=> "PROD"
event['datetime'] #=> "15307 23:58:12.13"
event['jobid'] #=> "JOB78035"
event['flag'] #=> "00000000"
event['messageid'] #=> "$HASP395"
event['logmessage'] #=> "$HASP395 GGIVJS27 ENDED\r"
This is the code I have currently:
message = event["message"];
if message.to_s != "" then
if message[2] == " " then
array = message.split(%Q[ ]);
event[%q[recordtype]] = array[0];
event[%q[routingcode]] = array[1];
event[%q[systemname]] = array[2];
event[%q[datetime]] = array[3] + " " +array[4];
event[%q[jobid]] = message[38,8];
event[%q[flags]] = message[47,8];
event[%q[messageid]] = message[57,8];
event[%q[logmessage]] = message[56..-1];
else
array = message.split(%Q[ ]);
event[%q[recordtype]] = array[0][0,2];
event[%q[routingcode]] = array[0][2..-1];
event[%q[systemname]] = array[1];
event[%q[datetime]] = array[2] + " "+array[3];
event[%q[jobid]] = message[38,8];
event[%q[flags]] = message[47,8];
event[%q[messageid]] = message[57,8];
event[%q[logmessage]] = message[56..-1];
end
end
I'm looking to improve the above code. I think I could use a regular expression, but I don't know how to approach it.
You can't use split(' ') or a default split to process your fields because you are dealing with columnar data that has fields that have no whitespace between them, resulting in your array being off. Instead, you have to pick apart each record by columns.
There are many ways to do that but the simplest and probably fastest, is indexing into a string and grabbing n characters:
'foo'[0, 1] # => "f"
'foo'[1, 2] # => "oo"
The first means "starting at index 0 in the string, grab one character." The second means "starting at index 1 in the string, grab two characters."
Alternately, you could tell Ruby to extract by ranges:
'foo'[0 .. 0] # => "f"
'foo'[1 .. 2] # => "oo"
These are documented in the String class.
This makes writing code that's easily understood:
record_type = message[ 0 .. 1 ].rstrip
routing_code = message[ 2 .. 8 ]
system_name = message[ 10 .. 17 ]
Once you have your fields captured add them to a hash:
{
'recordtype' => record_type,
'routingcode' => routing_code,
'systemname' => system_name,
'datetime' => date_time,
'jobid' => job_id,
'flags' => flags,
'messageid' => message_id,
'logmessage' => log_message,
}
While you could use a regular expression there's not much gained using one, it's just another way of doing it. If you were picking data out of free-form text it'd be more useful, but in columnar data it tends to result in visual noise that makes maintenance more difficult. I'd recommend simply determining your columns then cutting the data you need based on those from each line.

Evaluating code blocks in Rebol3

I'm trying to improve the Sliding Tile Puzzle example by making the starting positions random.
There's a better way to do this--"It is considered bad practice to convert values to strings and join them together to pass to do for evaluation."--but the approach I took was to try to generate Rebol3 source, and then evaluate it. I have it generating correctly, I think:
random/seed now
arr: random collect [ repeat tilenum 9 [ keep tilenum ] ]
hgroup-data: copy {}
repeat pos 9 [
curtile: (pick arr pos)
append hgroup-data either curtile = 9
[ reduce "x: box tilesize gameback " ]
[ rejoin [ { p "} curtile {" } ] ]
if all [(pos // 3) = 0 pos != 9] [ append hgroup-data " return^/" ]
]
print hgroup-data
...outputs something like:
p "4" x: box tilesize gameback p "5" return
p "3" p "7" p "1" return
p "2" p "8" p "6"
...which if I then copy and paste into this part, works correctly:
view/options [
hgroup [
PASTE-HERE
]
] [bg-color: gameback]
However, if I try to do it dynamically:
view/options [
hgroup [
hgroup-data
]
] [bg-color: gameback]
...(also print hgroup-data, do hgroup-data, and load hgroup-data), I get this error:
** GUI ERROR: Cannot parse the GUI dialect at: hgroup-data
...(or at: print hgroup-data, etc., depending on which variation I tried.)
If I try load [ hgroup-data ] I get:
** Script error: extend-face does not allow none! for its face argument
** Where: either if forever -apply- apply init-layout make-layout actor all foreach do-actor unless -apply- apply all build-face -apply- apply init-layout make-layout actor all foreach do-actor if build-face -apply- apply init-layout make-layout actor all foreach do-actor unless make-face -apply- apply case view do either either either -apply-
** Near: either all [
word? act: dial/1
block? body: get dial...
However, if I use the syntax hgroup do [ hgroup-data ], the program runs, but there are no buttons: it appears to be somehow over-evaluated, so that the return values of the functions p and box and so on are put straight into the hgroup as code.
Surely I'm missing an easy syntax error here. What is it?
First, I would say it's better to construct a block directly, instead of constructing a string and converting it to a block. But if you really want to do that, this should do the trick:
view/options compose/only [
hgroup (load hgroup-data)
] [bg-color: gameback]

How to I reference an array member in Ruby?

Given this array in Ruby:
myarray = [name: "John", age: 35]
How do I refer to the age?
I tried myarray[:age] but got an error can't convert Symbol into Integer
Update:
I was trying to simplify my question by extracting what I thought my problem is. I may not understand completely.
I'm experimenting with Dashing and trying to send a number to a meter widget. I've created a variable, 'response_raw' and am trying to send it in the third send event. Here's my code:
SCHEDULER.every '1m', :first_in => 0 do
# Get checks
url = "https://#{CGI::escape user}:#{CGI::escape password}#api.pingdom.com/api/2.0/checks"
`enter code here`response = RestClient.get(url, {"App-Key" => api_key})
response = JSON.parse(response.body, :symbolize_names => true)
if response[:checks]
checks = response[:checks].map { |check|
if check[:status] == 'up'
state = 'up'
last_response_time = "#{check[:lastresponsetime]}ms"
response_raw = check[:lastresponsetime]
else
state = 'down'
last_response_time = "DOWN"
response_raw = 0
end
{ name: check[:name], state: state, lastRepsonseTime: last_response_time, pt: response_raw }
}
else
checks = [name: "pingdom", state: "down", lastRepsonseTime: "-", pt: 0]
end
checks.sort_by { |check| check['name'] }
send_event('pingdom', { checks: checks })
send_event('pingdom-meter', { value: checks[:pt] })
end
In CoffeeScript [name: "John", age: 35] is an array containing single object with two properties (name and age).
Here is how it'll look in plain JavaScript:
myarray = [
{
name: "John",
age: 35
}
];
So, answering your question, to access an age you should take the first element of an array and then reference an age property:
myarray[0].age
or
myarray[0]['age']
But, judging from your question, your're probably using wrong data structure. Why don't you want to use a plain object instead of an array?
person = name: "John", age: 35
console.log "#{person.name}'s age is #{person.age}"
Update
It looks like your question is actually about Ruby and not about CoffeeScript. Though, my answer will remain the same.
To access an age you should take the first element of an array and then reference an age property:
myarray[0][:age]
Since myarray is an array, Ruby expects an integer index, but you're giving it symbol :age instead.
I finally figured it out with Leonid's help. Thank you.
I changed:
send_event('pingdom-meter', { value: checks[:pt] })
to
send_event('pingdom-meter', { value: checks[0][:pt] })

Resources