I have a chunk of code that has commands. I want to keep more commands in a separate file and pull them into the main. Thus my main file can be updated without losing any custom commands. How would I go about that?
{
class myClass()
#commands
listen_for /what is your name/i do
say "my name is mud"
end
## Insert Custom.rb here ##
# Everything in the custom rb file is just ike the "listen_for" command above
end
}
The answe above will not work in this case because there is no listen_for methods defined in the custom.rb file
wrap whatever you have in custom.rb in a module, like
module Foo
# commands
end
require your file custom.rb on the top of your script and include it in your class:
require_relative './custom.rb'
class myClass()
include Foo
# code here
end
This is the new try
Remove the module wrapper in the listen_for commands, and instead simply list them in the custom.rb as you would do inside your main class definition. And in your main class, Read and eval it, like this:
class myClass()
eval(File.read('./custom.rb'))
# code here
end
Related
In my Rails application I have a file sample_data.rb inside /lib/tasks as well as a bunch of test files inside my /spec directory.
All these files often share common functionality such as:
def random_address
[Faker::Address.street_address, Faker::Address.city].join("\n")
end
Where should I put those helper functions? Is there some sort of convention on this?
Thanks for any help!
You could create a static class, with static functions. That would look something like this:
class HelperFunctions
def self.random_address
[Faker::Address.street_address, Faker::Address.city].join("\n")
end
def self.otherFunction
end
end
Then, all you would need to do is:
include your helper class in the file you want to use
execute it like:
HelperFunctions::random_address(anyParametersYouMightHave)
When doing this, make sure you include any dependencies in your HelperFunctions class.
If you're sure it's rake only specific, you also can add in directly in RAILS_ROOT/Rakefile (that's probably not the case for the example you use).
I use this to simplify rake's invoke syntax :
#!/usr/bin/env rake
# Add your own tasks in files placed in lib/tasks ending in .rake,
# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
require File.expand_path('../config/application', __FILE__)
def invoke( task_name )
Rake::Task[ task_name ].invoke
end
MyApp::Application.load_tasks
That way, I can use invoke "my_namespace:my_task" in rake tasks instead of Rake::Task[ "my_namespace:my_task" ].invoke.
You share methods in a module, and you place such a module inside the lib folder.
Something like lib/fake_data.rb containing
module FakeData
def random_address
[Faker::Address.street_address, Faker::Address.city].join("\n")
end
module_function
end
and inside your rake task just require the module, and call FakeData.random_address.
But, if it is like a seed you need to do every time you run your tests, you should consider adding this to your general before all.
E.g. my spec_helper looks like this:
# Requires supporting ruby files with custom matchers and macros, etc,
# in spec/support/ and its subdirectories.
Dir[Rails.root.join("spec/support/**/*.rb")].each { |f| require f }
RSpec.configure do |config|
config.use_transactional_fixtures = true
config.infer_base_class_for_anonymous_controllers = false
config.order = "random"
include SetupSupport
config.before(:all) do
load_db_seed
end
end
and the module SetupSupport is defined in spec/support/setup_support.rb and looks as follows:
module SetupSupport
def load_db_seed
load(File.join(Rails.root, 'db', 'seeds.rb'))
end
end
Not sure if you need to load the seeds, or are already doing this, but this is the ideal spot to also generate needed fake data.
Note that my setup support class is defined in spec/support because the code is only relevant to my specs, I have no rake task also needing the same code.
How can I directly call a ruby function from the command-line?
Imagine, I would have this script test.rb:
class TestClass
def self.test_function(some_var)
puts "I got the following variable: #{some_var}"
end
end
If this script is run from the command-line (ruby test.rb), nothing happens (as intended).
Is there something like ruby test.rb TestClass.test_function('someTextString')?
I want to get the following output: I got the following variable: someTextString.
First the name of the class needs to start with a capital letter, and since you really want to use a static method, the function name definition needs to start with self..
class TestClass
def self.test_function(someVar)
puts "I got the following variable: " + someVar
end
end
Then to invoke that from the command line you can do:
ruby -r "./test.rb" -e "TestClass.test_function 'hi'"
If you instead had test_function as an instance method, you'd have:
class TestClass
def test_function(someVar)
puts "I got the following variable: " + someVar
end
end
then you'd invoke it with:
ruby -r "./test.rb" -e "TestClass.new.test_function 'hi'"
Here's another variation, if you find that typing ruby syntax at the command line is awkward and you really just want to pass args to ruby. Here's test.rb:
#!/usr/bin/env ruby
class TestClass
def self.test_function(some_var)
puts "I got the following variable: #{some_var}"
end
end
TestClass.test_function(ARGV[0])
Make test.rb executable and run it like this:
./test.rb "Some Value"
Or run it like this:
ruby test.rb "Some Value"
This works because ruby automatically sets the ARGV array to the arguments passed to the script. You could use ARGV[0] or ARGV.first to get the first argument, or you could combine the args into a single string, separated by spaces, using ARGV.join(' ').
If you're doing lots of command-line stuff, you may eventually have a use for Shellwords, which is in the standard ruby lib.
If you have multiple arguments to call in a example like this:
class TestClass
def self.test_function(some_var1, some_var2)
puts "I got the following variables: #{some_var1}, #{some_var2}"
end
end
run it like this (the arguments need to be comma separated in this case)
ruby -r "./test.rb" -e "TestClass.new.test_function 'hi','Mike'"
#!/usr/bin/env ruby
class A
def run
p :Hello_world
end
self
end.new.run
The usual way to script Ruby is to just use the top level execution environment called main. You can just start defining methods and code you write outside of a class, and these will be executed directly. (BTW, code inside a class but outside any method will run "by itself" also.)
Anyway, I'm with you ... I like writing all code in a named class and instantiating that class, so you can combine the techniques .. have the class return its own object .. and then use just a little of that top level code to allocate, initialize, and then dot into the class.
With this, you can just type $ ruby test.rb and it will do what you want. Or you can chmod +x test.rb; ./test.rb since we did add a shebang.
If you are working on a command line interface, then I would suggest to have a look at thor.
Thor directly maps your commands to methods within the defined class, see the thor wiki for an example.
Just an extension to Ingenu's answer for the case that the function does not print something out, but does return something.
We would have the following test.rb
class TestClass
def self.test_function(some_var)
return "I got the following variable: " + some_var
end
end
Then to invoke that from the command line and get the return value:
ruby -r "./test.rb" -e "puts TestClass.test_function('hi')"
If you know that how to call an rb file from commandline
ruby yourfile.rb
This can do the whole trick for you.
What you have done is, just defined your methods in the class. Now you can call it below the definition. If you still want to read, wide open your eyes
class TestClass
def self.test_function(some_var)
puts "I got the following variable: #{some_var}"
end
test_function(var)
end
I want to write a Ruby script something like this:
class Foo
# instance methods here
def self.run
foo = Foo.new
# do stuff here
end
end
# This code should only be executed when run as a script, but not when required into another file
unless required_in? # <-- not a real Kernel method
Foo.run
end
# ------------------------------------------------------------------------------------------
I want to be able to unit test it, which is why I don't want the code outside of the class to run unless I execute the script directly, i.e. ruby foo_it_up.rb.
I know I can simply put the Foo class in another file and require 'foo' in my script. In fact, that is probably a better way to do it, just in case Foo's functionality is needed somewhere else. So my question is more academic than anything, but I'd still be interested in knowing how to do this in Ruby.
This is usually done with
if __FILE__ == $0
Foo.run
end
but I prefer
if File.identical?(__FILE__, $0)
Foo.run
end
because programs like ruby-prof can make $0 not equal __FILE__ even when you use --replace-progname.
$0 refers to the name of the program ($PROGRAM_NAME), while __FILE__ is the name of the current source file.
I've placed a set of .rb files in a directory modules/. Each of these files contains a module. I'm loading all of these files from a separate script with this:
Dir["modules/*.rb"].each {|file| load file }
But then I have to include them, one by one, listing and naming each of them explicitly:
class Foo
include ModuleA
include ModuleB
# ... and so on.
end
I'm wondering if there is some non-explicit one-liner that can accomplish this, a la (pseudocode) ...
class Foo
for each loaded file
include the module(s) within that file
end
# ... other stuff.
end
I've considered actually reading the files' contents, searching for the string "module", and then extracting the module name, and somehow doing the include based on that -- but that seems ridiculous.
Is what I'm trying to do advisable and/or possible?
You can manually define some variable in each of your file and then check for its value while including the file.
For example, module1.rb:
export = ["MyModule"]
module MyModule
end
And the second one, module2.rb:
export = ["AnotherModule", "ThirdModule"]
module AnotherModule
end
module ThirdModule
end
And then just include all of them in your file (just the idea, it may not work correctly):
class Foo
Dir["modules/*.rb"].each do |file|
load file
if export != nil
export.each do { |m| include(Kernel.const_get(m))
end
end
end
I would expect it to be possible since you can place ruby code below class and include is also just a ruby call but you have to think of which module needs to be included where since your code is not the only one that loads and includes modules. And you wil not want to include all modules from the object space in your class.
So i personally would include them by name - you are adding funcionality to a class and by naming each module you document what is being added where.
And if you want this one liner: put a code in each module that adds its name to global list (remembering the disadvantages if using globals at all) and then iterate this list in the class definition to include all of them or part based on a criterium like name or what.
I am learning ruby and about modules and mixins..
I tried the following code. The name of the ruby file test.rb.
module Mod1
def Mod1.sayHello()
puts "Hello Mod1"
end
end
module Mod2
def Mod2.sayHello()
puts "Hello Mod2"
end
end
class TestMod
require 'file'
Mod1.sayHello
end
t = TestMod.new
I am suprised to the output:
Hello Mod1
Hello Mod1 (twice)
I am don't have an explanation for this, can somebody help?
You did not define your initialize method for your class (the constructor). You are simply executing Mod1.sayHello inside the class definition (it is even executed before creating the instance). Try to comment out your t = TestMod.new statement. The output will still stay visible.
Since you include the exact same file, this ends up being executed twice (the file does not get included another time afterwards; ruby prevents this). The class should look like this:
class TestMod
def initialize
Mod1.sayHello
end
end
Why did you include the file anyway? This does not make sense to me.
EDIT: Removed a mistake.
I would recommend to replace the Mod1 and Mod2 inside your module definitions with self. This way you wont have to change the name everywhere if it changes some time.