Wrong Number of Arguments in Initialize (given 0, expected 1) - ruby

I am following along with a tutorial at:
http://neurogami.com/content/neurogami-10_minutes_to_your_first_Ruby_app/#sidebar4
I have checked and rechecked the code, and I do not understand why ruby is not reading my variable app_map as a valid argument.
I have searched online for similar questions, and they exist, yet I can not understand why this variable is not working. I also am not exactly sure what initialize means, as I am an absolute beginner with Ruby. Any insight would be greatly appreciated.
#!/usr/bin/env ruby
class Launcher
def initialize (app_map)
#app_map = app_map
end
#execute the given file using the associate app
def run file_name
application = select_app file_name
system "#{application} #{file_name}"
end
#given a file, lookup the matching application
def select_app file_name
ftype = file_type file_name
#app_map[ ftype ]
end
#return the part of the file name string after the last '.'
def file_type file_name
File.extname( file_name ).gsub( /^\./, '' ).downcase
end
end
launcher = Launcher.new
end
I am not sure what this code is supposed to run, but I have multiple error messages.
tinyapp.rb:8:in `initialize': wrong number of arguments (given 0, expected 1) (ArgumentError)
from tinyapp.rb:30:in `new'
from tinyapp.rb:30:in `<main>'

In this line, you are instantiating a Launcher:
launcher = Launcher.new
That will call the initialize method on it. That method expects an argument:
def initialize (app_map)
#app_map = app_map
end
In order to resolve the error, you will need to pass in a parameter for the app_map argument. I don't know what it's supposed to actually be here, but that'll look something like this:
launcher = Launcher.new(the_app_map)

Related

YAML Ruby Load multiple environment variables

I inherited a tool that is working correctly but when I try to extend it it just fails. Since I am new to ruby and yaml I dont really know what is the reason why this fails...
So I have a class config that looks like this
class Configuration
def self.[] key
##config[key]
end
def self.load name
##config = nil
io = File.open( File.dirname(__FILE__) + "/../../../config/config.yml" )
YAML::load_documents(io) { |doc| ##config = doc[name] }
raise "Could not locate a configuration named \"#{name}\"" unless ##config
end
def self.[]=key, value
##config[key] = value
end
end
end
raise "Please set the A environment variable" unless ENV['A']
Helpers::Configuration.load(ENV['A'])
raise "Please set the D environment variable" unless ENV['D']
Helpers::Configuration.load(ENV['D'])
raise "Please set the P environment variable" unless ENV['P']
Helpers::Configuration.load(ENV['P'])
So I had a first version with the environment variable A that worked fine, then when I want to integrate 2 more environment variables it fails (they are different key/value sets). I did debug it and it looks like when it reads the second key/value it removes the other ones (such as reading the 3rd removes the previous 2, so I end up with ##config with only the 3rd key/value par instead of all the values I need).
It is probably easy to fix this, any idea how?
Thanks!
EDIT:
The config file use to look like:
Test:
position_x: “56”
position_y: “56”
Now I want to make it like
“x56”:
position_x: “56”
“x15”:
position_x: “15”
“y56”:
position_y: “56”
“y15”:
position_y: “15”
My idea is that I set them separately and I don’t need to create all the combinations…
Each time you call load you delete the previous configuration (in the line ##config = nil). If you want the configuration to be a merger of all files you will want to merge the new configuration to the existing configuration rather than overriding it.
Something like this:
def self.load name
##config ||= {}
io = File.open( File.dirname(__FILE__) + "/../../../config/config.yml" )
YAML::load_documents(io) do |doc|
raise "Could not locate a configuration named \"#{name}\"" unless doc[name]
##config.merge!(doc[name])
end
end
Be aware that if the code was written as it has been because the method was called more than once, and the configuration is expected to reset between reads, you will need to explicitly reset the configuration now:
class Configuration
# ...
def reset_configuration
#config = {}
end
end
Helpers::Configuration.reset_configuration
raise "Please set the A environment variable" unless ENV['A']
Helpers::Configuration.load(ENV['A'])
raise "Please set the D environment variable" unless ENV['D']
Helpers::Configuration.load(ENV['D'])
raise "Please set the P environment variable" unless ENV['P']
Helpers::Configuration.load(ENV['P'])
I'd access the YAML using:
YAML::load_file(File.expand_path("../../../config/config.yml", File.dirname(__FILE__)))
expand_path cleans up the '..' chain and returns the cleaned-up version, relative to FILE. For instance:
foo = '/path/to/a/file'
File.expand_path("../config.yml", File.dirname(foo)) # => "/path/to/config.yml"
load_file reads and parses the entire file and returns it.

How to add an object into another class? (Ruby)

I have ana assignment(which means that I have to be quite strict with what methods I use).
So I have this class File which simulates a file. All it does is - it conatains either nil or a single string, or a single symbol, or a single number or a single boolean (true/false). So I have a method that initializes a file, I also have a method data_type which determines the type (#class) of the contents of the file, a getter/setter, etc..
I also have this class Dictionary which may contain other directories and files. I should have the following methods inside of it:
add_file(name, file) - which adds a file named name. file should be an object of class File but we have no need to check whether the input object really belongs to this class.
add_directory(name, directory) - which adds a directory with the name name. directory is an object of class Directory. It may be missed, in which case an empty directory is created.
etc.. etc..
I have done all of my class File methods but I have a problem making the two methods I mention in class Directory. They have a lot of similarities so a comment on the add_file(name, file) one only should be enough.
All I could think of is name = File.new but not only does it not work but it also leaves out the file thing which I have totally no idea what is.
def add_file(name, file)
name = File.new
#name = name
end
This is, of course, highly incorrect but was all I could think of.
All help is appreciated. Thank you! And I'm sorry for asking so silly questions.
And remember, this is a simulation only! Those files aren't actual files. file is just a random name which fits. I highly doubt I should require anything!
EDIT: A friend of mine mentioned that the file probably already exists. I might just have to match it with this name. However.. I'm still highly confused.
EDIT2: Something in the lines of #files[name] = file with #files being a hash?
You might want to change the class File to a different name as there is already a File class.
Any way I'm guessing that that it works like this:
Ok, so I re-read your op and realised that Dictionary was a typo and thus redid the code so it now resembles:
class Directory
attr_accessor :name,:store
def initialize name
self.name = name
self.store = {}
end
def add_file(file)
self.store[file.name] = file
end
def add_directory(directory)
self.store[directory.name] = directory
end
def [](name)
self.store[name]
end
end
class File
attr_accessor :name, :content, :data_type
def initialize name,content = nil,data_type = nil
self.content = content
self.name = name
self.data_type = data_type || content.class
end
end
then you can do
file1 = File.new('hw.rb','puts "hello world!"', 'ruby file')
file2 = File.new('gbw.rb','puts "good bye world!"', 'ruby file')
root = Directory.new('root')
rb = Directory.new('rb')
rb.add_file(file1)
root.add_file(file2)
root.add_directory(rb)
puts root['rb']['hw.rb'].content
and if you used a splat operator argument in the add_file and add_directory methods you could then itterate through the argument and add each file so you could use it like
file1 = File.new('hw.rb','puts "hello world!"', 'ruby file')
file2 = File.new('gbw.rb','puts "good bye world!"', 'ruby file')
root = Directory.new('root')
root.add_file(file1,file2)
research 'ruby splat operator arguments' for information on what I mean

Unable to run regex on file content after putting it?

I have created a simple class to handle opening, reading, and closing a file. In addition, I would like to run a regex on its contents to find a 4 digit date. However, when I run my code I get the following error:
file_class.rb:17:in `find_date': undefined method `match' for nil:NilClass (NoMethodError)
from file_class.rb:24:in `<main>'
This error only occurs if I run the read_file method before it, which simply puts the file contents. I am not sure why doing so would result in such an error.
Below is my code:
class MyFile
attr_reader :handle
def initialize(filename)
#handle = File.open(filename)
end
def read_file
puts #handle.gets
end
def finished
#handle.close
end
def find_date
matching = #handle.gets.match(/\d{4}/)
puts matching[0]
end
end
f = MyFile.new('text.txt')
f.read_file
f.find_date
f.finished
Thanks for the help.
I'm guessing your file had a single line of contents.
When you call gets on an open file handle, the handle returns the line it is currently looking at and moves its "cursor" down to the next line. After you've read the last line, gets will return nil.
Your class would be better (for a few reasons) if you read the file once and cache the contents, rather than caching the handle and attempting to read several times:
class MyFile
attr_reader :contents
def initialize(filename)
File.open(filename) do |f|
#contents = f.read
end
end
def find_date
matching = #contents.match(/\d{4}/)
puts matching[0]
end
end
This approach is better because:
You only need to read the file once.
You're reading the whole file at once, not one line at a time (File#read instead of File#gets).
Your class has better encapsulation - other code that wants to use it doesn't need to tell your class to read the file, then find a date, then close the file - all of the logic is internal to your class.
You need to write less code - attr_accessor makes contents available to calling code without you needing to write your own methods. This is good because it's quicker to write and, much more importantly, it's clearer to read.

Accessing/Dealing with Variables in Ruby

Let me preface by stating I'm a "new" programmer - an IT guy trying his hand at his first "real" problem after working through various tutorials.
So - here is what I'm trying to do. I'm watching a directory for a .csv file - it will be in this format: 999999_888_filename.csv
I want to return each part of the "_" filename as a variable to pass on to another program/script for some other task. I have come up w/ the following code:
require 'rubygems'
require 'fssm'
class Watcher
def start
monitor = FSSM::Monitor.new(:directories => true)
monitor.path('/data/testing/uploads') do |path|
path.update do |base, relative, ftype|
output(relative)
end
path.create do |base, relative, ftype|
output(relative)
end
path.delete { |base, relative, ftype| puts "DELETED #{relative} (#{ftype})" }
end
monitor.run
end
def output(relative)
puts "#{relative} added"
values = relative.split('_',)
sitenum = values[0]
numrecs = values[1]
filename = values[2]
puts sitenum
end
end
My first "puts" gives me the full filename (it's just there to show me the script is working), and the second puts returns the 'sitenum'. I want to be able to access this "outside" of this output method. I have this file (named watcher.rb) in a libs/ folder and I have a second file in the project root called 'monitor.rb' which contains simply:
require './lib/watcher'
watcher = Watcher.new
watcher.start
And I can't figure out how to access my 'sitenum', 'numrecs' and 'filename' from this file. I'm not sure if it needs to be a variable, instance variable or what. I've played around w/ attr_accessible and other things, and nothing works. I decided to ask here since I've been spinning my wheels for a couple of things, and I'm starting to confuse myself by searching on my own.
Thanks in advance for any help or advice you may have.
At the top of the Watcher class, you're going to want to define three attr_accessor declarations, which give the behavior you want. (attr_reader if you're only reading, attr_writer if you're only writing, attr_accessor if both.)
class Watcher
attr_accessor :sitenum, :numrecs, :filename
...
# later on, use # for class variables
...
#sitenum = 5
...
end
Now you should have no problem with watcher.sitenum etc. Here's an example.
EDIT: Some typos.
In addition to Jordan Scales' answer, these variable should initialized
class Watcher
attr_accessor :sitenum, :numrecs, :filename
def initialize
#sitenum = 'default value'
#numrecs = 'default value'
#filename = 'default value'
end
...
end
Otherwise you'll get uninformative value nil

Ruby Class, I suspect I am doing instance markers wrong

I want this class to initialize to receive a message to be saved and enter a filename for it. Am I drawing up an error because Ruby only wants values to be instantiated in the init method? Be gentle, I'm new to this. Traceback pasted below.
class DobbsyKretts
idea = 'arbitaryvalue'
def initialize
#Receive idea
puts "Enter an idea, a secret or anything else you want to encrypt. Hit enter to stop typing and save the file"
#idea.gets.reverse.upcase
#Filename and saving - to encrypt the file.
puts "Enter the file name you'd like to have this saved as. Type PLAN at the beginning for plans and REM for reminders"
#file_name.gets.strip
File::open("DobbsyKrett-"+ file_name + ".txt", "w") do |f|
f>>#idea
end
end
end
something = DobbsyKretts.new
Traceback:
testy.rb:11:in `initialize': private method `gets' called for nil:NilClass (NoMethodError)
from testy.rb:21:in `new'
from testy.rb:21:in `<main>'
Enter an idea, a secret or anything else you want to encrypt. Hit enter to stop typing and save the file
You are calling getson #idea before having assigned a value - that's one of the reasons why you get the error. Also, gets should not be called on the instance variable here. Try it like this:
class DobbsyKretts
def initialize
#Receive idea
puts "Enter an idea, a secret or anything else you want to encrypt. Hit enter to stop typing and save the file"
(#idea = gets).reverse.upcase
#Filename and saving - to encrypt the file.
puts "Enter the file name you'd like to have this saved as. Type PLAN at the beginning for plans and REM for reminders"
#file_name = gets.strip
File::open("DobbsyKrett-"+ #file_name + ".txt", "w") do |f|
f << #idea
end
end
end
something = DobbsyKretts.new
This works as you expected, but I just would like to remind you that it is a very bad idea to do something like this in the constructor. You should rather use a dedicated method for generating files and/or asking the user for input.
gets is either a Kernel#gets or IO#gets (I will omit ARGF#gets for brevity), #idea in your case is not an IO object (by default any instance variable is set to nil), and calling Kernel#gets with explicit receiver is prohibited. So correct code is #idea = gets.

Resources