Split seeds.rb into multiple sections? - ruby

I'd like to split my seeds.rb file into multiple sections for ease of maintenance; seed all the A's in a.rb, the B's in b.rb, etc. The separate files are located in the db/ directory with seeds.rb. Each file consists of a bunch of "A.create" or "B.create" calls and I want to call those files from seeds.rb.
I've tried:
include 'a'
include 'b'
and
load 'a.rb'
load 'b.rb'
in my seeds.rb but they don't seem to be processed when I call "rake db:seed". This is probably more of a straight ruby question than a rails question but for completeness I'm using Ruby 1.9.2 and Rails 3 on a Mac.

In ./db/seeds/my_module.rb:
module MyModule
puts "In my_module.rb"
# add code here
end
In ./db/seeds.rb:
require File.expand_path('../seeds/my_module', __FILE__) # the ../ just removes `seeds.rb` filename from the path which is given by __FILE__
p "In seeds.rb"
# add code here

I would propose to create a new db/seeds/ directory where you can place your various seeds file:
db/seeds/01_stuff_that_comes_for_first.rb
db/seeds/02_stuff_that_comes_for_second.rb
...
And then edit your db/seeds.rb file with:
Dir[File.join(Rails.root, 'db', 'seeds', '*.rb')].sort.each { |seed| load seed }
So, you can load your seeds even in the order you prefer - that is often something requested.
This solution was originally proposed by nathanvda in this "duplicated" question.

Related

Is there a need for require-only files and modules.rb files?

I've been assigned to perform some maintenance on an existing Ruby gem project. I'm not native to Ruby, but there are files that to me appear to be unnecessary.
Let's say that folder a/b/c is the root of the project, representing module A::B::C. There are also sub modules A::B::C::D1, A::B::C::D2, A::B::C::D3, etc.
The first file that I don't find logical is file modules.rb in folder a/b/c. This contains an empty module declaration for every module in the entire project:
module A::B::C
end
module A::B::C::D1
end
module A::B::C::D2
end
# etc
I tried to find out what this file is for, but I couldn't find any mentions anywhere on Google apart from examples where the modules.rb actually contains all of the code (e.g. https://github.com/shrinidhi99/learn-ruby-for-fun/blob/master/Modules.rb, https://borg.garasilabs.org/andrew/ruby-training/-/blob/master/codes/modules.rb, https://zetcode.com/lang/rubytutorial/oop2/). There's also no reference to it anywhere in the project itself. The only thing it appears to achieve is to provide documentation on rubydoc.info. That can probably be inlined in the separate files.
Besides that, most modules M have a matching file m.rb that sits besides the m folder. For example, file a/b/c.rb, a/b/c/d1.rb, etc. This file contains nothing except require statements of all files in the matching module. That means that file a/b/c.rb also has require statements for a/b/c/d1 etc.
There are two sub modules of A::B::C that are not included in these require files, and these modules have several sub modules of their own. That, combined with the fact that each file should just mention it requirements itself, indicates that these require files are completely unnecessary. The only reason I can think of is mentioned here: https://stackoverflow.com/a/26470550/
Am I wrong in thinking that I can simply remove these files, or are they still necessary? Or is this something that's just "the Ruby way"?
Something like this should work. One file -- one class (or module). If you have namespace and there is general logic in it -- separate file for the namespace
# a.rb
Dir[File.join(__dir__, 'a', '*.rb')].each { |f| require f }
module A
# general A logic here
end
# a/b.rb
Dir[File.join(__dir__, 'b', '*.rb')].each { |f| require f }
module A
module B
# general A::B logic here
end
end
# a/b/c.rb
module A
module B
module C
end
end
end
# a/b/d.rb
module A
module B
module D
end
end
end
# x.rb
require_relative 'a'
class X
include A::B::C
end

Calling classes from files

I am writing a program which includes two file. I’m the first file all I am doing is initializing the next file which includes multiple classes. I call the class at the bottom of the file, but it runs the class at the top of the file.
Btw I am running ruby
First file:
Require ‘./secondfile.rb’
newfile.Lastclass
Second file:
class Firstclass
end
class Lastclass
end
Hint #1. It's better to write without .
It depends on directory from where you run your app.
For example you have directory folder. And there you have two files:
file.rb
puts "I'm file.rb"
main.rb
require './file.rb'
If you run your app from folder - it's ok:
folder$ ruby main.rb
I'm file.rb
But if you'll run it from high level - it will be error:
folder$ cd ..
:~$ ruby folder/main.rb
kernel_require.rb:55:in `require': cannot load such file -- ./file.rb (LoadError)
But how to write in this case?
Hint #2. You can use special method
main.rb
require "./#{__dir__}/file.rb"
Now it's ok in all cases:
~$ ruby folder/main.rb
I'm file.rb
folder$ ruby main.rb
I'm file.rb
But you can write it better.
Hint #3. You can use require_relative
main.rb
require_relative 'file.rb'
And even better.
main.rb
require_relative 'file'
Ruby understand it.
~$ ruby folder/main.rb
I'm file.rb
folder$ ruby main.rb
I'm file.rb
Hope this helps you.
Classes are injected into the root namespace if they're defined. If another file defines a class, all files get it:
require_relative './secondfile.rb'
Lastclass
This is unlike JavaScript (e.g. Node.js) where you must explicitly import classes from other files. In Ruby it happens by manipulating the root namespace.
Another note is to pay close attention to which slashes you use. In your code you used a backslash, which is incorrect. You also used the wrong quotes. Often every character counts when programming.

Dynamic require_relative in test_helper not working

I've been battling for an hour with a require_relative in my test_helper.rb that I just can't seem to get to work.
Given a project structure like so
lib
|-- square_digits.rb
test
|-- test_square_digits.rb
|-- test_helper.rb
And these test files:
# test/test_square_digits.rb
require 'test_helper'
# test/test_helper.rb
require "minitest/autorun"
Dir.glob('../lib/**/*.rb').each { |f| require_relative f }
# require_relative "../lib/square_every_digit.rb"
I cannot get my tests to run correctly with the dynamic require, but directly requiring with the hardcoded path does function as intended, though the Dir.glob does seem to catch the file (while running pry in test/)
$ pry(main)> Dir.glob('../lib/**/*.rb')
$ => ["../lib/square_every_digit.rb"]
I have tried the require_relative gem, Dir[] and various solutions to no avail...
Have you tried generating the lines of code and using eval
baseDir = __dir__+"/RGSS Classes"
fileCol = Dir.children(baseDir)
fileCol.each do |library|
libPath = baseDir+"/"+library
code = "require '"+libPath+"'"
puts code
eval(code)
end
you wont be able to use require_reletive because it'll give a "LoadError: cannot infer basepath", i am unsure if it's the same reason as stated in this answer but using require worked
first need to get the current file location using __dir__ and then append whatever subfolder the files you want to require are. then you loop though the results generating the line of code for each file (i choose to generate the path in a variable first before adding it to the code)
obviously since eval is executing string as code if this is used outside of personal private use you'd might want to add some sanitization to the file names as a bad or maliciously named file will execute as code.
alternatively you can forgo using eval and have it output each line to a .rb file which you would then require which eliminates the risk of filenames being used to inject code

How can I tell which file is being required here? [duplicate]

This question already has answers here:
What happens technically when a file is required in Ruby?
(3 answers)
Closed 5 years ago.
I'm reading through the codebase of the Homebrew repo, specifically the file here:
https://github.com/Homebrew/brew/blob/8518ffdee19c0c985e8631e836b78624e4926c7f/Library/Homebrew/brew.rb
I see many 'require' statements scattered throughout the file, for instance on line 104 (require 'tap'). The problem is that I see 3 files named tap.rb in the codebase:
Library/Homebrew/tap.rb
Library/Homebrew/cmd/tap.rb
Library/Homebrew/compat/tap.rb
Further down in the code I see Tap.fetch..., and in Library/Homebrew/tap.rb which contains a class named Tap with a class method named fetch, so I'm confident this is the correct file that's being included. But conceivably, there could be dozens of files with the same filename, and more than one of those could have identical class methods. My question is, is there a way to tell which Tap class is being loaded without looking through each of the files?
UPDATE: I think I have the answer to my question (see below).
If you put a binding.pry before the require and execute $: that will be the list of directories in which the require will look up the 'tap.rb' files.
See definition of require:
If the filename does not resolve to an absolute path, it will be searched for in the directories listed in $:.
I found this great explanation of how require works in Ruby:
https://github.com/ericmathison/articles/blob/master/understaning-require-in-ruby.md
Essentially, it works by looking at the Ruby $LOAD_PATH method, similar to how UNIX uses the $PATH variable to look for binary executables when it receives a command in the CLI. I was able to test this out on my local by making two files in the same directory, like so:
# file number 1- foobar.rb
module Foobar
module_function
def bar
p "foo"
end
end
# file number 2- foobaz.rb
$LOAD_PATH.unshift(".")
class Foobaz
def baz
require 'foobar'
p Foobar.bar
end
end
Foobaz.new.baz
Without the line $LOAD_PATH.unshift(".") in foobaz.rb, the code wouldn't execute with the simple require 'foobar' statement. I instead had to use require_relative 'foobar.rb'. But adding the current working directory to the $LOAD_PATH environment variable meant that I now had access to all the ruby files in the current dir, so it executed!
NB- it's likely that adding . to the $LOAD_PATH should go in a config file somewhere, not in the same file as the require statement.

What is the difference between require_relative and require in Ruby?

What is the difference between require_relative and require in Ruby?
Just look at the docs:
require_relative complements the builtin method require by allowing you to load a file that is relative to the file containing the require_relative statement.
For example, if you have unit test classes in the "test" directory, and data for them under the test "test/data" directory, then you might use a line like this in a test case:
require_relative "data/customer_data_1"
require_relative is a convenient subset of require
require_relative('path')
equals:
require(File.expand_path('path', File.dirname(__FILE__)))
if __FILE__ is defined, or it raises LoadError otherwise.
This implies that:
require_relative 'a' and require_relative './a' require relative to the current file (__FILE__).
This is what you want to use when requiring inside your library, since you don't want the result to depend on the current directory of the caller.
eval('require_relative("a.rb")') raises LoadError because __FILE__ is not defined inside eval.
This is why you can't use require_relative in RSpec tests, which get evaled.
The following operations are only possible with require:
require './a.rb' requires relative to the current directory
require 'a.rb' uses the search path ($LOAD_PATH) to require. It does not find files relative to current directory or path.
This is not possible with require_relative because the docs say that path search only happens when "the filename does not resolve to an absolute path" (i.e. starts with / or ./ or ../), which is always the case for File.expand_path.
The following operation is possible with both, but you will want to use require as it is shorter and more efficient:
require '/a.rb' and require_relative '/a.rb' both require the absolute path.
Reading the source
When the docs are not clear, I recommend that you take a look at the sources (toggle source in the docs). In some cases, it helps to understand what is going on.
require:
VALUE rb_f_require(VALUE obj, VALUE fname) {
return rb_require_safe(fname, rb_safe_level());
}
require_relative:
VALUE rb_f_require_relative(VALUE obj, VALUE fname) {
VALUE base = rb_current_realfilepath();
if (NIL_P(base)) {
rb_loaderror("cannot infer basepath");
}
base = rb_file_dirname(base);
return rb_require_safe(rb_file_absolute_path(fname, base), rb_safe_level());
}
This allows us to conclude that
require_relative('path')
is the same as:
require(File.expand_path('path', File.dirname(__FILE__)))
because:
rb_file_absolute_path =~ File.expand_path
rb_file_dirname1 =~ File.dirname
rb_current_realfilepath =~ __FILE__
Summary
Use require for installed gems
Use require_relative for local files
require uses your $LOAD_PATH to find the files.
require_relative uses the current location of the file using the statement
require
Require relies on you having installed (e.g. gem install [package]) a package somewhere on your system for that functionality.
When using require you can use the "./" format for a file in the current directory, e.g. require "./my_file" but that is not a common or recommended practice and you should use require_relative instead.
require_relative
This simply means include the file 'relative to the location of the file with the require_relative statement'. I generally recommend that files should be "within" the current directory tree as opposed to "up", e.g. don't use
require_relative '../../../filename'
(up 3 directory levels) within the file system because that tends to create unnecessary and brittle dependencies. However in some cases if you are already 'deep' within a directory tree then "up and down" another directory tree branch may be necessary. More simply perhaps, don't use require_relative for files outside of this repository (assuming you are using git which is largely a de-facto standard at this point, late 2018).
Note that require_relative uses the current directory of the file with the require_relative statement (so not necessarily your current directory that you are using the command from). This keeps the require_relative path "stable" as it always be relative to the file requiring it in the same way.
From Ruby API:
require_relative complements the
builtin method require by allowing you
to load a file that is relative to the
file containing the require_relative
statement.
When you use require to load a file,
you are usually accessing
functionality that has been properly
installed, and made accessible, in
your system. require does not offer a
good solution for loading files within
the project’s code. This may be useful
during a development phase, for
accessing test data, or even for
accessing files that are "locked" away
inside a project, not intended for
outside use.
For example, if you have unit test
classes in the "test" directory, and
data for them under the test
"test/data" directory, then you might
use a line like this in a test case:
require_relative "data/customer_data_1"
Since neither
"test" nor "test/data" are likely to
be in Ruby’s library path (and for
good reason), a normal require won’t
find them. require_relative is a good
solution for this particular problem.
You may include or omit the extension
(.rb or .so) of the file you are
loading.
path must respond to to_str.
You can find the documentation at http://extensions.rubyforge.org/rdoc/classes/Kernel.html
The top answers are correct, but deeply technical. For those newer to Ruby:
require_relative will most likely be used to bring in code from another file that you wrote.
for example, what if you have data in ~/my-project/data.rb and you want to include that in ~/my-project/solution.rb? in solution.rb you would add require_relative 'data'.
it is important to note these files do not need to be in the same directory. require_relative '../../folder1/folder2/data' is also valid.
require will most likely be used to bring in code from a library someone else wrote.
for example, what if you want to use one of the helper functions provided in the active_support library? you'll need to install the gem with gem install activesupport and then in the file require 'active_support'.
require 'active_support/all'
"FooBar".underscore
Said differently--
require_relative requires a file specifically pointed to relative to the file that calls it.
require requires a file included in the $LOAD_PATH.
I just saw the RSpec's code has some comment on require_relative being O(1) constant and require being O(N) linear. So probably the difference is that require_relative is the preferred one than require.
I want to add that when using Windows you can use require './1.rb' if the script is run local or from a mapped network drive but when run from an UNC \\servername\sharename\folder path you need to use require_relative './1.rb'.
I don't mingle in the discussion which to use for other reasons.
absolute path
require './app/example_file.rb'
shortened name
require_relative 'example_file'

Resources