I have been running rubocop and encountered a Lint/Void: Literal used in void context offence.
the following code:
routes_and_postcodes.each do |hash|
2..7.each do |i|
route = Route.where(name: hash[:route]).first if postcode.delete(" ").first(i) == hash[:postcode].delete(" ")
end
end
I have read the docs, but still cant understand what the issue is.
In context, the full code is here:
def choose_own_van_route(postcode)
route = nil
routes_and_postcodes = []
Route.all.each do |r|
route_postcodes = r.postcode_array
route_postcodes.each do |pc|
routes_and_postcodes << { postcode: pc, route: r.name }
end
end
routes_and_postcodes.each do |hash|
2..7.each do |i|
route = Route.where(name: hash[:route]).first if postcode.delete(" ").first(i) == hash[:postcode].delete(" ")
end
end
route || Route.create(cut_off_time_mins_since_midnight: 0, name: "BLANK ROUTE HAD TO BE ASSIGNED")
end
Thanks
2..7.each do |i|
# ...
end
...is invalid code!! Have you tried running it? You'll see the following error:
NoMethodError: undefined method `each' for 7:Integer
To fix this, you need to define the Range in brackets:
(2..7).each do |i|
# ...
end
The rubocop error is in relation to this: Since if there were an each method defined on Integer (there isn't, but rubocop doesn't know that), then the code would be valid but the 2..<something> range definition would serve no purpose; it's a literal with a void context.
Related
My code
require "json"
require "erb"
flowvar = $workflowvar
path = 'src/main/resources/'+$workflowvar+'.drl'
rule = ""
File.open(path,"w") do |f|
f.puts "package com.drools.demo\;"+"\n"+"import org.mule.MessageExchangePattern\;"+"\n"+"import com.drools.demo.cashliquidassets\;"+"\n"+"global org.mule.module.bpm.MessageService mule\;"+"\n"+
"dialect \"mvel\""+"\n"+"dialect \"java\""+"\n"+"declare cashliquidassets"+"\n"+"#role\(\'event\'\)"+"\n"+"end"+"\n"
f.close
end
def concateRule(attribute,val)
if(val==null || val=="")
return "";
end
if(attribute != null)
if (attribute == "taxonomy_code" || attribute == "parent_taxonomy_code" || attribute == "report_name")
return "";
end
end
if val.start_with('<>')
return attribute+" != "+val[3,val.length].strip
elsif val.start_with('>')
return attribute+" > "+val
elsif val.start_with('<')
return attribute+" < "+val
elsif val.include? ","
return attribute+".contains("+val+"\)"
else
return attribute+" == "+ val
end
end
json = JSON.parse($payload)
json.each do |hash1|
hash1.keys.each do |key|
hash1[key].each do |inner_hash,value|
#inner_hash = inner_hash
#values = value
str = concateRule #inner_hash,$values
end
end
end
Compile is working fine, but in runtime, I am getting this following error. Any suggestions
Root Exception stack trace:
org.jruby.exceptions.RaiseException: (NameError) undefined local
variable or method `null' for main:Object
at RUBY.concateRule(<script>:15)
at RUBY.block in (root)(<script>:43)
at org.jruby.RubyHash.each(org/jruby/RubyHash.java:1350)
at RUBY.block in (root)(<script>:40)
at org.jruby.RubyArray.each(org/jruby/RubyArray.java:1735)
at RUBY.block in (root)(<script>:39)
at org.jruby.RubyArray.each(org/jruby/RubyArray.java:1735)
at RUBY.<main>(<script>:38)
You need to use nil instead of null.
So, just replace it.
Following the conversation in the comments above, here is how I would write the method:
def concat_rule(attribute, val)
val = val.to_s
if val == '' || ['taxonomy_code', 'parent_taxonomy_code', 'report_name'].include?(attribute)
return ''
end
if val.start_with?('<>')
"#{attribute} != #{val[3..-1].strip}"
elsif val.start_with?('>')
"#{attribute} > #{val}"
elsif val.start_with?('<')
"#{attribute} < #{val}"
elsif val.include?(',')
"#{attribute}.contains(#{val})"
else
"#{attribute} == #{val}"
end
end
A few notes:
Using snake_case method names and 2 space tabs, is a very strongly adhered to style guide in the ruby community.
Similarly, you can make use of ruby's implicit return, to shorten the code: The final value at the end of a method is returned automatically.
Adding val = val.to_s to the top of this method simplifies the rest of the code; eliminating the need to repeatedly convert to a string or perform nil checks.
You can use ruby's string interpolation ("#{code-to-evaluate}") syntax as a more elegant way to define strings than repeated use of + for concatenation.
The following returns the default "client?":
class ClientMap
def initialize
##clients = {"DP000459": "BP"}
##clients.default = "client?"
end
def get(id)
return ##clients[:id]
end
end
clientMap = ClientMap.new
cKey = "DP000459"
puts clientMap.get(cKey)
Could anybody explain why I cannot retrieve anything but the 'default'?
You've got two problems. First, you are using the symbol syntax in your hash, which works only if your keys are symbols. If you want keys to be strings, you need to use hash-rocket syntax: ##clients = {'DP000459' => 'BP'}.
Second, your method returns clients[:id] regardless of what parameter is provided. The key is the symbol :id rather than the local variable id. You need to change this to ##clients[id].
Here's a cleaned-up version of what you want:
class ClientMap
def initialize
##clients = {'DP000459' => 'BP'}
##clients.default = 'client?'
end
def get(id)
##clients[id]
end
end
I've also taken the liberty of making the spacing more Ruby-idiomatic.
Finally, for variable names in Ruby, use snake_case:
>> client_map = ClientMap.new
>> c_key = 'DP000459'
>> client_map.get(c_key)
#> "BP"
Look at these code:
h = { foo: 'bar' } # => {:foo=>"bar"}
h.default = 'some default value' # => "some default value"
h[:foo] # => "bar"
h[:non_existing_key] # => "some default value"
You can read here about Hash#default method
Returns the default value, the value that would be returned by hsh if
key did not exist in hsh
I am getting the following error:
ShowsQueryObject querying for a show by start date returns shows that are after the start date
Failure/Error: expect(ShowsQueryObject.query(start_date: start_date)).to match_array [after_start_date_show_1, after_start_date_show_2]
NoMethodError:
undefined method `query_params' for ShowsQueryObject:Class
For this code:
class ShowsQueryObject
class << self
def query(query_params)
Show.where(query_string(query_params), query_values(query_params))
end
private
def query_string(query_params)
query_string = []
query_string << start_date_query if query_params(:start_date)
query_string << end_date_query if query_params(:end_date)
query_string << artist_name_query if query_params(:artist_name)
query_string << venue_id_query if query_params(:venue_id)
query_string.join(' AND ')
end
def query_values(query_params)
{}.tap do |hash|
hash[:start_date] = query_params(:start_date) if query_params(:start_date)
hash[:end_date] = query_params(:end_date) if query_params(:end_date)
hash[:artist_name] = query_params(:artist_name) if query_params(:artist_name)
hash[:venue_id] = query_params(:venue_id) if query_params(:venue_id)
end
end
...
end
end
I am guessing this has something to do with private static methods in Ruby? This is my first time messing around with class << self so I'm assuming I did something wrong, but from what I can find on line this all looks legit to me.
You should try changing query_params(:start_date) to query_params[:start_date], because if you put it with "()" ruby takes it as a method and not a property
I encounter a strange problem when trying to alter values from a Hash. I have the following setup:
myHash = {
company_name:"MyCompany",
street:"Mainstreet",
postcode:"1234",
city:"MyCity",
free_seats:"3"
}
def cleanup string
string.titleize
end
def format
output = Hash.new
myHash.each do |item|
item[:company_name] = cleanup(item[:company_name])
item[:street] = cleanup(item[:street])
output << item
end
end
When I execute this code I get: "TypeError: no implicit conversion of Symbol into Integer" although the output of item[:company_name] is the expected string. What am I doing wrong?
Your item variable holds Array instance (in [hash_key, hash_value] format), so it doesn't expect Symbol in [] method.
This is how you could do it using Hash#each:
def format(hash)
output = Hash.new
hash.each do |key, value|
output[key] = cleanup(value)
end
output
end
or, without this:
def format(hash)
output = hash.dup
output[:company_name] = cleanup(output[:company_name])
output[:street] = cleanup(output[:street])
output
end
This error shows up when you are treating an array or string as a Hash. In this line myHash.each do |item| you are assigning item to a two-element array [key, value], so item[:symbol] throws an error.
You probably meant this:
require 'active_support/core_ext' # for titleize
myHash = {company_name:"MyCompany", street:"Mainstreet", postcode:"1234", city:"MyCity", free_seats:"3"}
def cleanup string
string.titleize
end
def format(hash)
output = {}
output[:company_name] = cleanup(hash[:company_name])
output[:street] = cleanup(hash[:street])
output
end
format(myHash) # => {:company_name=>"My Company", :street=>"Mainstreet"}
Please read documentation on Hash#each
myHash.each{|item|..} is returning you array object for item iterative variable like the following :--
[:company_name, "MyCompany"]
[:street, "Mainstreet"]
[:postcode, "1234"]
[:city, "MyCity"]
[:free_seats, "3"]
You should do this:--
def format
output = Hash.new
myHash.each do |k, v|
output[k] = cleanup(v)
end
output
end
Ive come across this many times in my work, an easy work around that I found is to ask if the array element is a Hash by class.
if i.class == Hash
notation like i[:label] will work in this block and not throw that error
end
If the value:
myhash['first_key']['second_key']
exists, then I need to get it. But 'second_key' may not be present at all in my_hash, and I don't want that line to throw an exception if it is not.
Right now I am wrapping the whole thing in an ugly conditional like so:
if myhash['first_key'].present? and myhash['first_key']['second_key'].present?
...
end
I'm sure there must be something simpler.
You can always use try:
hsh.try(:[], 'first_key').try(:[], 'second_key')
FYI: if you're doing a lot of these checks, you might want to refactor your code to avoid these situations.
When in doubt, write a wrapper:
h = {
first_key: {
second_key: 'test'
}
}
class Hash
def fetch_path(*parts)
parts.reduce(self) do |memo, key|
memo[key] if memo
end
end
end
h.fetch_path(:first_key, :second_key) # => "test"
h.fetch_path(:first_key, :third_key) # => nil
h.fetch_path(:first_key, :third_key, :fourth_key) # => nil
h.fetch_path(:foo, :third_key) # => nil
Try this neat and clean solution. Hash default values:
h = Hash.new( {} ) # sets a hash as default value
Now do what you like:
h[:some_key] # => {}
h[:non_existent_key][:yet_another_non_existent_key] # => nil
Nice?
Say you have an existing hash, which is already populated:
h = { a: 1, b: 2, c: 3 }
So you just set its default to return a new hash:
h.default = {}
And there you go again:
h[:d] # => {}
h[:d][:e] # => nil
I'd point you to the excellent Hashie::Mash
An example:
mash = Hashie::Mash.new
# Note: You used to be able to do : `mash.hello.world` and that would return `nil`
# However it seems that behavior has changed and now you need to use a `!` :
mash.hello!.world # => nil # Note use of `!`
mash.hello!.world = 'Nice' # Multi-level assignment!
mash.hello.world # => "Nice"
# or
mash.hello!.world # => "Nice"
You could set up some default values before processing the hash. Something like:
myhash[:first_key] ||= {}
if myhash[:first_key][:second_key]
# do work
end
Why not define a method for this?
class Hash
def has_second_key?(k1,k2)
self[k1] ? self[k1][k2] : nil
end
end
new_hash = {}
new_hash["a"] = "b"
new_hash["c"] = {"d"=>"e","f"=>"g"}
new_hash[:p] = {q:"r"}
new_hash.has_second_key?("r","p")
# =>nil
new_hash.has_second_key?("c","f")
# =>"g"
new_hash.hash_second_key?(:p,:q)
# =>"r"
To modify your code, it would be:
if myhash.has_second_key?('first-key','second-key')
...
end
This method will return nil, which is Falsey in Ruby, or will return the value of the second key which is Truthy in Ruby.
Obviously you do not have to modify the Hash class if you don't want to. You could have the method except the hash as an argument too. has_second_key?(hash,k1,k2). Then call it as:
has_second_key?(myhash,'first-key','second-key')