my question is that if i have a class CSVWriter inside a file named csv_writer.rb, then can i instantiate this class using my filename dynamically.
I did tried using Object.const_get() method but it takes the name of the class as string as argument.
So is there anyway to do that in ruby
Thanks
You can use the __FILE__ constant to get the name of the file.
# foo.rb
puts __FILE__
Output
"foo.rb"
Knowing this, you could do something like
# csv_writer.rb
class CsvWriter
def initialize
puts "hello"
end
end
klass = Object.const_get(
File::basename(__FILE__, ".rb")
.split("_")
.map(&:capitalize)
.join("")
)
klass.new
Output
"hello"
PS there's no programmatic way to convert csv_writer to CSVWriter. How would ruby know to capitalize csv to CSV (all-caps) but writer to only Writer?
Related
Good morning...evening.
The problem is about calling method with given argument straightaway after typing in command line:
$ ruby my_class.rb someString
I have got a file my_class.rb with code:
class MyClass
p ARGV
end
and that works, but I would like to use a method to print that input:
class MyClass
def print_me(string)
p string
end
end
Is it even possible to do it without specifying class and method in command line and keep it that way?
$ ruby my_class.rb someString
Yes, just define your class and then call it with the arguments like this:
class MyClass
def print_me(string)
p string
end
end
MyClass.new.print_me(ARGV[0])
You can put the last line in a different file that requires your class definition. But this just changes how you manage your code.
I am trying to mock file read with the help of StringIO in Ruby.
The following is my test and next to that is my method in the main class.
def test_get_symbols_from_StringIO_file
s = StringIO.new("YHOO,141414")
assert_equal(["YHOO,141414"], s.readlines)
end
def get_symbols_from_file (file_name)
IO.readlines(file_name, ',')
end
I want to know if this is the way we mock the file read and also I would like to know if there is some other method to mock the method in the class rather than doing assert equal with contents.
Your method get_symbols_from_file is never called in the test. You're just testing that StringIO#readlines works, i.e.:
StringIO.new("YHOO,141414").readlines == ["YHOO,141414"] #=> true
If you want to use a StringIO instance as a placeholder for your file, you have to change your method to take a File instance rather than a file name:
def get_symbols_from_file(file)
file.readlines(',')
end
Both, File and StringIO instances respond to readlines, so the above implementation can handle both:
def test_get_symbols_from_file
s = StringIO.new("YHOO,141414")
assert_equal(["YHOO,141414"], get_symbols_from_file(s))
end
This test however fails: readlines includes the line separator, so it returns an array with two elements "YHOO," (note the comma) and "141414". You are expecting an array with one element "YHOO,141414".
Maybe you're looking for something like this:
def test_get_symbols_from_file
s = StringIO.new("YHOO,141414")
assert_equal(["YHOO", "141414"], get_symbols_from_file(s))
end
def get_symbols_from_file(file)
file.read.split(',')
end
If you really want to use IO::readlines you could create a Tempfile:
require 'tempfile'
def test_get_symbols_from_file
Tempfile.open("foo") { |f|
f.write "YHOO,141414"
f.close
assert_equal(["YHOO", "141414"], get_symbols_from_file(f.path))
}
end
I have a file, 'example.rb', where I want to use custom methods on String by overriding the string class.
I know this can be done as
puts "abcd".twice
class String
def twice
self*2
end
end
But I want to have the custom methods definition in another file, say 'my_String.rb'. How do I do this?
Do your monkey patching in "my_string.rb" (or whatever) and have the file required in your script.
# my_string.rb
class String
def twice
self*2
end
end
# my_super_script.rb
require 'my_string.rb' # Assuming both these files are in the same folder
puts "abcd".twice
You simply put the String class opening method in my_string.rb and in your code you do:
require 'my_string'
I would like to put a large variable definition in a separate file for the sake of getting it out of the way. I must be doing something wrong though, because my puts call isn't putting anything out.
my_class.rb:
class foobar
def initialize
require 'datafile.rb'
puts #fat_data
end
end
datafile.rb:
#fat_data = [1,2,3,4,5,6,7,8,9,10]
Can you use require this way?
You can do something like this:
my_class.rb:
class Foobar
def initialize
init_fat_data
puts #fat_data
end
end
datafile.rb:
class Foobar
private
def init_fat_data
#fat_data = [1,2,3,4,5,6,7,8,9,10]
end
end
Or, perhaps, change class Foobar in datafile.rb to module MyData and then include the module to Foobar class in my_class.rb.
If you just want to get the data out of the class definition, you could also use __END__ and DATA:
Useless Ruby Tricks: DATA and __END__
I'm trying to redefine the File.dirname method to first change %20s to spaces. But the following gives me an error
class File
old_dirname = instance_method(:dirname)
define_method(:dirname) { |s|
s = s.gsub("%20"," ")
old_dirname.bind(self).call(s)
}
end
This trhows a NameError exception: undefined method 'dirname' for class 'File'
What is the right way to do this?
As Chuck already wrote, File::dirname is a singleton method of the File class object (or more precisely an instance method of the File class object's metaclass), not an instance method of the File class.
So, you have to open up File's metaclass, not the File class itself:
#!/usr/bin/env ruby
class << File
old_dirname = instance_method :dirname
define_method :dirname do |*args|
old_dirname.bind(self).(*args).gsub '%20', ' '
end
end
require 'test/unit'
class TestFileDirname < Test::Unit::TestCase
def test_that_it_converts_percent20_to_space
assert_equal '/foo bar/baz', File.dirname('/foo%20bar/baz/quux.txt')
end
end
However, I agree with #sheldonh: this breaks the API contract of File::dirname.
Just be careful.
You're changing the behaviour of the method, not just its implementation. This is generally poor practice, because it weakens the value of the API as a dependable contract.
Instead, consider transforming the input closer to the point of receipt.
dirname is a class method of File, not an instance method, so you're just defining a new instance method. Also, the idiomatic way to alias a method is with alias. So:
class <<File
alias old_dirname dirname
def dirname(f)
old_dirname(f.gsub("%20", " "))
end
end
The class <<whatever syntax adds methods to an individual object — in this case, the File class.