Ruby on rails formatting number - ruby

I want a number to be printed like "42/100". This formatting should be done by a function which I am gonna use in two different models. where should I add that method?

Okay, as per the limited description, here is what i propose:
formatting_helper.rb
module FormattingHelper
MAXIMUM_VALUE = 100.freeze # Change it here.
def self.divide_by_maximum_value(str)
"#{str}/#{MAXIMUM_VALUE}"
end
end
And then you will be able to call FormattingHelper.divide_by_maximum_value from anywhere. e.g.
FormattingHelper.divide_by_maximum_value('42')
=> "42/100"

If you want to create a number to percentage you can use
number helper from ruby on rails official guide
number_to_percentage(42)
# => 42.000%
except those guide, you should create module like jagdeep singth said.
or create lambda
num_formatter = ->(x,y='100') { x.to_s+"/#{y.to_s}" }
num_formatter.call(42)
# => "42/100"
num_formatter.call(42,1000)
# => "42/1000"

Related

Creating nested Puppet fact (Ruby) by iterating over gem query output

I have working Ruby code to query DNS details and create Puppet custom facts (puppet 5, Facter 3.11.6) however I am trying to modify it to create nested facts from the key/value pairs that the query obtains.
Code that works to set individual facts with the key name is:
require 'resolv'
Resolv::DNS::Config.default_config_hash.each do | key, value |
if !value.nil?
Facter.add("dns_#{key}") do
if value.is_a?(Array)
setcode { value.join(',') }
else
setcode { value }
end
end
end
end
which creates individual facts thus:
dns_nameserver => 192.168.1.1,192.168.1.2
dns_ndots => 1
dns_search => test.domain
My failed attempt so far to create a nested fact under the parent fact of 'DNS' is:
require 'resolv'
Facter.add("dns") do
value ={}
Resolv::DNS::Config.default_config_hash.each do | key, result |
if !result.nil?
if result.is_a?(Array)
setcode { value['#{key}'] = result.join(',') }
else
setcode { value['#{key}'] = result }
end
end
end
end
which gives a limited result of just:
dns => 1
Other code I have tried seems to put an array output into the string and multiple IPs are quoted inside square brackets over 2 lines instead of being output as per the first code block at top of page.
The fact structure I am TRYING to achieve (by modifying the top of page code) is:
dns => {
nameserver => 192.168.1.1,192.168.1.2,
ndots => 1,
search => test.domain,
}
Thanks in advance for any assistance.
I finally got this with the assistance from a poster who put some great code leads here, but unfortunately removed it soon afterward. Here is the code that works:
require 'resolv'
Facter.add(:networking_dns) do
setcode do
Resolv::DNS::Config.default_config_hash.each_with_object({}) do | (key, value), sub|
if !value.nil?
sub[key] = value
sub
end
end
end
end
Now for some explanatory notes (please feel free to correct me or offer any optimisations to this):
# the resolv gem is required
require 'resolv'
# create the parent fact (has no value of its own)
Facter.add(:networking_dns) do
# start building instructions in the fact
setcode do
# use the resolv gem to lookup values in /etc/resolv.conf and add .each to process all key/value pairs returned
# also add _with_object({}) and sub in the variables to set a blank value for sub. Saves doing it separately. Sub can be any name but denotes the declaration for the nested facts
Resolv::DNS::Config.default_config_hash.each_with_object({}) do | (key, value), sub|
# create facts only when the value is not nil
if !value.nil?
sub[key] = value
sub
# using a closing blank entry for a nested fact is critical or they won't create! Place this outside of the case statement to prevent blank values
end
end
end
end
# use the appropriate number of ends and indent for readability
Thanks to the person who posted their guidance here before removing it. I would like to upvote you if you post again.
Any tips on optimisation to the able solution are welcome, as I'm still grasping Ruby (spent hours on this!)

What are the equivalent to Lodash's get and set in Ruby?

I would like to use something similar to Lodash's get and set, but in Ruby instead of JavaScript. I tried few searches but I can't find anything similar.
Lodash's documentation will probably explain it in a better way, but it's getting and setting a property from a string path ('x[0].y.z' for example). If the full path doesn't exist when setting a property, it is automatically created.
Lodash Set
Lodash Get
I eventually ported Lodash _.set and _.get from JavaScript to Ruby and made a Gem.
Ruby 2.3 introduces the new safe navigator operator for getting nested/chained values:
x[0]&.y&.z #=> result or nil
Otherwise, Rails monkey patches all objects with try(…), allowing you to:
x[0].try(:y).try(:z) #=> result or nil
Setting is a bit harder, and I'd recommend ensuring you have the final object before attempting to set a property, e.g.:
if obj = x[0]&.y&.z
z.name = "Dr Robot"
end
You can use the Rudash Gem that comes with most of the Lodash utilities, and not only the _.get and _.set.
Sometimes I have had the need to programmatically get the value for a property deep into an object, but the thing is that sometimes the property is really a method, and sometimes it needs parameters!
So I came up with this solution, hope it helps devising one for your problem:
(Needs Rails' #try)
def reduce_attributes_for( object, options )
options.reduce( {} ) do |hash, ( attribute, methods )|
hash[attribute] = methods.reduce( object ) { |a, e| a.try!(:send, *e) }
hash
end
end
# Usage example
o = Object.new
attribute_map = {
# same as o.object_id
id: [:object_id],
# same as o.object_id.to_s
id_as_string: [:object_id, :to_s],
# same as o.object_id.to_s.length
id_as_string_length: [:object_id, :to_s, :length],
# I know, this one is a contrived example, but its purpose is
# to illustrate how you would call methods with parameters
# same as o.object_id.to_s.scan(/\d/)[1].to_i
second_number_from_id: [:object_id, :to_s, [:scan, /\d/], [:[],1], :to_i]
}
reduce_attributes_for( o, attribute_map )
# {:id=>47295942175460,
# :id_as_string=>"47295942175460",
# :id_as_string_length=>14,
# :second_number_from_id=>7}

Not able to call instance_double twice

I'm writing a test fot rspec to check that items are added into a class that I use like an array
describe '#collection' do
let(:process) {
instance_double("WebServerProcess", :cpu => 33, :mem => 22, :pid => 1, :port => 8000)
}
it 'return the collection' do
WebServersCollection.add process
expect(subject.collection).to eq([process])
end
it 'should add with <<' do
WebServersCollection << process
expect(subject.collection).to eq([process])
end
end
Show me this error
Failure/Error: expect(subject.collection).to eq([process])
# was originally created in one example but has leaked into another example and can no
longer be used. rspec-mocks' doubles are designed to only last for one
example, and you need to create a new one in each example you wish to
use it for.
I think the error tells you everything you need to know.
You can't do that and
you need to create a new one in each example you wish to use it for

Sinatra: User.first method

I'm reading a book that's making a Twitter clone with Sinatra in order to improve my knowledge of Ruby. I'm puzzled by the author's use of
User.first(:nickname => params[:recipient])
which he uses in several locations throughout the code, as in the following example.
post '/message/send' do
recipient = User.first(:nickname => params[:recipient])
Status.create(:text => params[:message], :user => User.
get(session[:userid]), :recipient => recipient)
redirect '/messages/sent'
end
What exactly is 'first' adding to this method. For example, is it searching for the first user with the nickname passed in as the parameter :recipient? In other words, is it equivalent to 'find'?
I should add that it puzzles me also because the nicknames are supposed to be unique, so there's no reason why it would need to search for the 'first' if that's indeed what it's doing.
Update
The author is using DataMapper for the ORM
Ok, 'first' is a datamapper method that 'finds'. From the docs
zoo = Zoo.first(:name => 'Metro') # first matching record with the name 'Metro'

How do I re-pass multiple method arguments in Ruby 1.8.5?

I'm using ruby 1.8.5 and I'd like to use a helper method to help filter a user's preferences like this:
def send_email(user, notification_method_name, *args)
# determine if the user wants this email
return if !user.send("wants_#{notification_method_name}?")
# different email methods have different argument lengths
Notification.send("deliver_#{notification_method_name}", user, *args)
end
This works in ruby 1.8.6, however when I try to do this in 1.8.5 and try to send more than one arg I get an error along the lines of:
wrong number of arguments (2 for X)
where X is the number of arguments that particular method requires. I'd rather not rewrite all my Notification methods - can Ruby 1.8.5 handle this?
A nice solution is to switch to named-arguments using hashes:
def send_email(args)
user = args[:user]
notification_method_name = args[:notify_name]
# determine if the user wants this email
return if !user.send("wants_#{notification_method_name}?")
# different email methods have different argument lengths
Notification.send("deliver_#{notification_method_name}", args)
end
send_email(
:user => 'da user',
:notify_name => 'some_notification_method',
:another_arg => 'foo'
)

Resources