Ruby in 100 Minutes, good_morning method - ruby

I have been doing the Ruby in 100 minutes website, and encountered a problem during part 5.
I was asked to create a good_morning method that would print out a greeting such as 'Happy Monday, it's the 130 day of 2013'. Here is my current program:
class PersonalChef
def good_morning
date = Time.new
today = Time("%A")
day_of_year = Time.yday
this_year = Time("%Y")
puts "Happy " + "#{today}" + "! It is the " + "#{day_of_year}" + " day of the year" + "#{this_year}"
return self
end
def make_toast(color)
puts "Making your toast #{color}!"
return self
end
def make_milkshake(flavor)
puts "Don\'t worry boss, my #{flavor} milkshake brings all the boys to the yard!"
return self
end
def make_eggs(quantity)
puts "Making you #{quantity} eggs sir!"
return self
end
end
but when I run the program via irb (load 'personal_chef.rb', frank = PersonalChef.new, frank.make_milkshake('chocolate'), etc, everything works fine until I try to type frank.good_morning into irb, which gives the following error message
"NoMethodError: undefined method Time' for #<PersonalChef:0x00000001b61808>
from personal_chef.rb:4:ingood_morning'
from (irb):3
from /usr/bin/irb:12:in `'
I tried substituting the Date method instead of Time and still encountered the same problem.
Thanks for reading, and hopefully for your forthcoming helpful advice! If there is more information that would be helpful to solve this issue, please let me know.

The line of code
today = Time("%A")
uses Time, the class, as a method call, which explains the error. I see that you are trying to extract the day name and the day of year from a time object, but passing the format string to Time isn't the way to do it.
You are looking for the strftime method.
Example:
>> today = Time.new()
=> 2013-06-19 21:58:34 -0700
>> today.strftime("%A")
=> "Wednesday"
>> today.strftime("%j")
=> "170"
Wednesday, the 170th day of the year.

Related

chef: how to get a timestamp at *convergence* rather than *compile* time

Please consider this code at the end of my deploy_to_tomcat recipe:
unless Chef::Config[:solo]
chat_message "Deployed #{artifact_name} `#{Time.new.strftime("%Y-%m-%d %H:%M")}`"
end
It posts a message to chat: Deployed my-web-app 2016-11-03 12:31
However, I notice the timestamp from Time.new is a little out - it seems to be the timestamp when the recipe was compiled, rather than when the resources coverged and ran, a couple of minutes later.
So I tried this, but it didn't work (timeNow was still undefined when message was posted to chat)
timeNow = "undefined"
ruby_block "set-time-now" do
block do
timeNow = Time.new.strftime("%Y-%m-%d %H:%M:%S")
end
end
unless Chef::Config[:solo]
chat_message "Deployed #{artifact_name} `#{timeNow}`"
end
Is there an easier way to get my timestamp to reflect the actual time (rather than when the recipe started) ?
What you want is a lazy evaluator like this (give or take that I don't know how your chat_message resource is written):
unless Chef::Config[:solo]
chat_message "deployed" do
message lazy { "Deployed #{artifact_name} `#{Time.new.strftime("%Y-%m-%d %H:%M")}`" }
end
end
That will delay evaluation of the message string until converge time.
Not sure what you try to solve, but you can use node to store timestamp.
node.normal[:cookbook_name][:deployment_time] = "undefined"
ruby_block "set-time-now" do
block do
node.normal[:cookbook_name][:deployment_time] = Time.new.strftime("%Y-%m-%d %H:%M:%S")
end
end
unless Chef::Config[:solo]
chat_message "Deployed #{artifact_name} #{node[:cookbook_name][:deployment_time]}"
end

Ruby: file output blank

So I'm trying to build a program which tells me how many days are left till someone's birthday. I have a text file that I'm drawing data from. The problem is the save method is not working for some reason, and nothing is being printed to the output file. Thank you so much in advance!
require 'date'
Person = Struct.new(:name, :bday)
module Family
Member = Hash.new
File.readlines("bday_info.txt").each do |line|
name, bday = line.split(',')
person = Person.new(name, bday)
Member[name] = bday
end
def self.next_bday(name)
birthday = Date.parse(Family::Member[name])
this_year = Date.new(Date.today.year, birthday.month, birthday.day)
next_year = Date.new(Date.today.year + 1, birthday.month, birthday.day)
if this_year > Date.today
puts "\n#{(this_year - Date.today).to_i} days to #{name}'s birthday"
else
puts "\n#{(next_year - Date.today).to_i} days to #{name}'s birthday"
end
end
def self.save(name)
File.open("days_left.txt", "w") do |file|
file.puts "#{next_bday(name)}"
end
end
end
loop do
puts "\nName:"
response = gets.chomp.capitalize
if response.downcase == "quit"
break
elsif Family::Member.has_key?("#{response}") == false
puts "\nYou ain't on the list"
else
Family.next_bday(response)
Family.save(response) #WHY IS THIS LINE NOT WORKING???
end
end
Your Family.next_bday does not return anything (to be more precise - it's returning nil that last puts returns), thus nothing is written to the file.
Other notes(not directly related):
No reason in calling Family.next_bday(response) twice, just save return value from the first call
Family::Member constant looks more like a variable, more clean design will be to make the whole thing a class that takes input file name, reads data in initializer and then stores into a instance variable

loop through json array and retrieve one attribute, gives errors also

i am new to programming in ruby, and i am trying to get the value of json['earning_rate_hr'] but i get an error, in '[]': no implicit conversion of String into Integer (TypeError)
i know and i understand the error, however this is not my main question here is my file :
checkingchecker.rb :
#require_relative '../lib/hackex/net/typhoeus'
require_relative '../lib/hackex'
require 'rubygems'
require 'json'
file = 'accounts1.txt'
f = File.open file, 'r'
puts "MADE BY THE PEOPLE, FOR THE PEOPLE #madebylorax"
puts ""
puts "--------------------------------------------------------"
puts ""
while line = f.gets
line = line.chomp.split(';')
email, password = line
puts "logging in as " + email
HackEx.LoginDo(email, password) do |http, auth_token, user|
puts "getting info..."
user = HackEx::Request.Do(http, HackEx::Request.UserInfo(auth_token))['user']
puts "receieved user info!"
bank = HackEx::Request.Do(http, HackEx::Request.UserBank(auth_token))['user_bank']
puts "recieved bank info!"
json = HackEx::Request.Do(http, HackEx::Request.UserSpam(auth_token))['spam']
puts "recieved spam info!"
puts json['earning_rate_hr'] #error line, the error is because this is an array, and it cant be turned into integer, i was wondering if there is a way to use puts on it without trying to make it an integer
userchecking = bank["checking"]
checking = userchecking.scan(/.{1,3}/).join(',')
puts email + " has in Checking: BTC #{checking}"
puts ""
puts "--------------------------------------------------------"
puts ""
end
end
i tried to do puts json, it puts items like this one :
{"id"=>"9867351", "user_id"=>"289108", "victim_user_id"=>"1512021",
"victim_ip"=
"86.60.226.175", "spam_level"=>"50", "earning_rate_hr"=>"24300", "total_earning s"=>"13267800", "started_at"=>"2015-11-01 07:46:59",
"last_collected_at"=>"2015- 11-24 01:46:59"}
what i want to do is select the earning_rate_hr for each one of them and add them together, however i do not have a clue on how to do that, since the error is not fixed and i cant get the value of it
ps : i tried turning it into a Hash, and i also tried using .first, but .first only shows the firs one, i want to show all of them, thank you
I know you from line messenger, I haven't used ruby codes in a long time and this one keeps giving me cloudflare errors, I'm not sure if its because of server downtime/maintainance or whatever but yeah anyway heres your script, enjoy farming ;) -LineOne
PS, I changed a few strings to make it look a lil cleaner so you can see the spam income easier, and added the sleep (1) because sleeping for one second before reconnecting helps to prevent cloudflare errors
also you don't need to require json or rubygems in your hackex scripts because its required in the library so its all covered pre-user-input/script
require_relative 'libv5/lib/hackex'
while 1<2
begin
print'Filename: '
fn=gets.chomp
file = fn+'.txt'
f = File.open file, 'r'
puts "MADE BY THE PEOPLE, FOR THE PEOPLE #madebylorax" #helped by lineone
puts ""
puts "--------------------------------------------------------"
puts ""
while line = f.gets
line = line.chomp.split(';')
email, password = line
HackEx.LoginDo(email, password) do |http, auth_token, user|
puts "Retrieving Info..."
puts''
user = HackEx::Request.Do(http, HackEx::Request.UserInfo(auth_token))['user']
bank = HackEx::Request.Do(http, HackEx::Request.UserBank(auth_token))['user_bank']
json = HackEx::Request.Do(http, HackEx::Request.UserSpam(auth_token))['spam']
cash_count=0
tot_count=0
json.each do |j|
earn_rate = j['earning_rate_hr']
total= j['total_earnings']
cash_count+=earn_rate.to_i
tot_count+=total.to_i
end
print "#{email}: current earnings: #{cash_count} per hour, Total earnings #{tot_count},"
userchecking = bank["checking"]
checking = userchecking.scan(/.{1,3}/).join(',')
puts " #{checking} BTC in Checking"
puts ""
puts "--------------------------------------------------------"
puts ""
sleep 1
end
end
rescue
puts"#{$!}"
end
end
Thats fine you can also calculate the total income of your farms by adding new variables at the top example a=0 then adding the number at the end a+=tot_count
This should help:
earning_rates = json.map{|e| e["earning_rate_hr"]}
puts "Earning rates per hour: #{earning_rates.join(" ")}"
puts "Sum of earning rates: #{earning_rates.map{|e| e.to_i}.inject{|sum, x| sum + x}}"

How do I represent morning and midnight timings in ruby?

I need to store and retrieve restaurant timings in simple methods like morning and midnight. What I am doing now is:
def morning
Time.new("6:30 am")
end
def midnight
Time.new("12:00 am")
end
I can compare timings now but this seems to be the wrong way to do it and then I don't know how to read those time values back for a method like:
def open?(time)
time >= morning && time <= midnight
end
What is the right way to do this?
Using the chronic gem I was able to do this:
def opens_at
morning
end
def closes_at
midnight
end
def open?(time)
Chronic.parse(time) >= morning && Chronic.parse(time) < midnight
end
private
def morning
Chronic.parse("6:30 am")
end
def midnight
Chronic.parse("midnight")
end
This works for comparisons
For people like me who do not like having a extra gem in gemfile for smaller things, will go for:
def morning
DateTime.now.beginning_of_day + (6.5).hours
end
def midnight
DateTime.now.end_of_day
# Or DateTime.now.at_midnight + 1
end
there are a lot more options DateTime gives us like:
:at_beginning_of_day, :at_beginning_of_month, :at_beginning_of_quarter, :at_beginning_of_week, :at_beginning_of_year, :at_end_of_month, :at_end_of_quarter, :at_end_of_week, :at_end_of_year, :at_midnight, :awesome_inspect, :awesome_print, :beginning_of_day, :beginning_of_month, :beginning_of_quarter, :beginning_of_week, :beginning_of_year, :wday, :sunday?, :monday?, :tuesday?, :wednesday?, :thursday?, :friday?, :saturday?
Just do( trust me you wont regret it):
DateTime.now.methods.sort

get next/previous month from a Time object

I have a Time object and would like to find the next/previous month. Adding subtracting days does not work as the days per month vary.
time = Time.parse('21-12-2008 10:51 UTC')
next_month = time + 31 * 24 * 60 * 60
Incrementing the month also falls down as one would have to take care of the rolling
time = Time.parse('21-12-2008 10:51 UTC')
next_month = Time.utc(time.year, time.month+1)
time = Time.parse('01-12-2008 10:51 UTC')
previous_month = Time.utc(time.year, time.month-1)
The only thing I found working was
time = Time.parse('21-12-2008 10:51 UTC')
d = Date.new(time.year, time.month, time.day)
d >>= 1
next_month = Time.utc(d.year, d.month, d.day, time.hour, time.min, time.sec, time.usec)
Is there a more elegant way of doing this that I am not seeing?
How would you do it?
Ruby on Rails
Note: This only works in Rails (Thanks Steve!) but I'm keeping it here in case others are using Rails and wish to use these more intuitive methods.
Super simple - thank you Ruby on Rails!
Time.now + 1.month
Time.now - 1.month
Or, another option if it's in relation to the current time (Rails 3+ only).
1.month.from_now
1.month.ago
Personally I prefer using:
Time.now.beginning_of_month - 1.day # previous month
Time.now.end_of_month + 1.day # next month
It always works and is independent from the number of days in a month.
Find more info in this API doc
you can use standard class DateTime
require 'date'
dt = Time.new().to_datetime
=> #<DateTime: 2010-04-23T22:31:39+03:00 (424277622199937/172800000,1/8,2299161)>
dt2 = dt >> 1
=> #<DateTime: 2010-05-23T22:31:39+03:00 (424282806199937/172800000,1/8,2299161)>
t = dt2.to_time
=> 2010-05-23 22:31:39 +0200
There are no built-in methods on Time to do what you want in Ruby. I suggest you write methods to do this work in a module and extend the Time class to make their use simple in the rest of your code.
You can use DateTime, but the methods (<< and >>) are not named in a way that makes their purpose obvious to someone that hasn't used them before.
If you do not want to load and rely on additional libraries you can use something like:
module MonthRotator
def current_month
self.month
end
def month_away
new_month, new_year = current_month == 12 ? [1, year+1] : [(current_month + 1), year]
Time.local(new_year, new_month, day, hour, sec)
end
def month_ago
new_month, new_year = current_month == 1 ? [12, year-1] : [(current_month - 1), year]
Time.local(new_year, new_month, day, hour, sec)
end
end
class Time
include MonthRotator
end
require 'minitest/autorun'
class MonthRotatorTest < MiniTest::Unit::TestCase
describe "A month rotator Time extension" do
it 'should return a next month' do
next_month_date = Time.local(2010, 12).month_away
assert_equal next_month_date.month, 1
assert_equal next_month_date.year, 2011
end
it 'should return previous month' do
previous_month_date = Time.local(2011, 1).month_ago
assert_equal previous_month_date.month, 12
assert_equal previous_month_date.year, 2010
end
end
end
below it works
previous month:
Time.now.months_since(-1)
next month:
Time.now.months_since(1)
I just want to add my plain ruby solution for completeness
replace the format in strftime to desired output
DateTime.now.prev_month.strftime("%Y-%m-%d")
DateTime.now.next_month.strftime("%Y-%m-%d")
You can get the previous month info by this code
require 'time'
time = Time.parse('2021-09-29 12:31 UTC')
time.prev_month.strftime("%b %Y")
You can try convert to datetime.
Time gives you current date, and DateTime allows you to operate with.
Look at this:
irb(main):041:0> Time.new.strftime("%d/%m/%Y")
=> "21/05/2015"
irb(main):040:0> Time.new.to_datetime.prev_month.strftime("%d/%m/%Y")
=> "21/04/2015"
Here is a solution on plain ruby without RoR, works on old ruby versions.
t=Time.local(2000,"jan",1,20,15,1,0);
curmon=t.mon;
prevmon=(Time.local(t.year,t.mon,1,0,0,0,0)-1).mon ;
puts "#{curmon} #{prevmon}"
Some of the solutions assume rails. But, in pure ruby you can do the following
require 'date'
d = Date.now
last_month = d<<1
last_month.strftime("%Y-%m-%d")
Im using the ActiveSupport::TimeZone for this example, but just in case you are using Rails or ActiveSupport it might come in handy.
If you want the previous month you can substract 1 month
time = Time.zone.parse('21-12-2008 10:51 UTC')
time.ago(1.month)
$ irb
irb(main):001:0> time = Time.now
=> 2016-11-21 10:16:31 -0800
irb(main):002:0> year = time.year
=> 2016
irb(main):003:0> month = time.month
=> 11
irb(main):004:0> last_month = month - 1
=> 10
irb(main):005:0> puts time
2016-11-21 10:16:31 -0800
=> nil
irb(main):006:0> puts year
2016
=> nil
irb(main):007:0> puts month
11
=> nil
irb(main):008:0> puts last_month
10
=> nil

Resources