Reading the YARD documentation and questions like this one I see this is a very nice tool to document functions, classes, and methods, but I fail to figure out how to document a simple script such as:
# #description Read files in folder and print their sizes
# #author Mefitico
require_relative '../lib/my_funcs'
# Check files in folder and print their sizes:
Dir.entries(Dir.pwd).select do |file|
if File.file?(file)
puts "#{file} - #{File.size(file)} bytes"
end
end
puts "Finished script"
Doing so generates no documentation whatsoever because no functions or classes are being defined. But for the project I'm working on, I need to create documentation for several standalone scripts which call for functions defined elsewhere. These scripts need to be documented nicely, and cannot be refactored into functions, modules or classes.
Related
First, I'm not attempting to test a module. I'm testing classes within a single module. This SO question/answer doesn't describe the code I'm looking at, so it's tough to draw parallels to my curiosity.
I'm following along with this tutorial, which is outdated; However, it's a suggested resource.
My specific question is:
Why is the RSpec language in the spec file placed within the module TicTacToe, like so:
require 'some_file'
module TicTacToe
#RSpec examples here
end
I'm very new to RSpec and coding in general, so I'm not familiar with the conventions of writing tests in RSpec; Is this organization necessary? Out-dated? My tests are passing and things are working as expected; I'm just attempting to learn how to write tests, and most specs begin with RSpec.describe Foo do or describe Bar do
I have not seen module used like that within spec files. I suspect that's a very old tutorial. (Wordpress helpfully shows it's from Oct 25, but neglects to mention which year. But the oldest comment is from 2014)
I recommend you find a more recent tutorial.
The describe keyword would be more appropriate here. Most of the specs I work with looked like this a few years ago:
RSpec.describe TicTacToe::SomeClass, type: :model do
#RSpec examples here
end
Or even more modern, rspec discerns the type (model, controller, etc.) from the path to the spec file:
# spec/model/tic_tac_toe/cell.rb
describe Cell do
let(:first_cell) { described_class.new }
#RSpec examples here
end
Let's say I have an Application that requires different files. Each file contains a single purpose "thing". I call it "thing" because I'm unsure if it will be a class or a module.
The First Thing
# things/one.rb
class One
def self.do_it
"I'm the one"
end
end
And the second
# things/two.rb
class Two
def self.do_it
"I'm not the only one!"
end
end
Now I wanna require all files in the thingsdirectory and execute the do_it method. But I wanna do this dynamically - for every thing in things folder without even knowing their Classname.
# app.rb
Dir["things/*.rb"].each {|file| require file }
Keep in Mind: I simply wanna execute the code in the things files - it's not necessary that they are Classes or Modules
You can't reliably do this for a number of reasons, but the most important is that you're under no obligations to declare a single class in any given file, or a class at all. You've got the right idea with loading in all files in a particular directory, but if you need to operate on those there's two ways to crack that nut.
The easiest way is to declare these classes as a subclass of some already known parent. ActiveSupport has the descendents method to reflect on a particular class, that's part of Rails, but you can also do it the hard way if you have to.
The second easiest way is to correlate the names with the classes in them, and then convert filenames to class-names algorithmically. This is how the Rails autoloader works. cat.rb contains Cat, bad_dog.rb contains BadDog and so on.
If you look more closely at how things like Test::Unit work they take the first approach, any declared test subclasses are executed before the Ruby process terminates. It's a fairly simple system that puts no constraints on what the files are called or where and how the classes are declared.
Rails leans towards the second approach where the path communicates intent. This makes finding files more predictable but requires more discipline on the part of the developer to conform to that standard.
They both have merit. Pick the one that works for your use case.
I've developed a set of Ruby scripts. Each of them should be 'self-contained', so a user can run it on its own. But also I would like to use them to build other scripts, I mean for example to use its methods but also to run it as a whole, without doing ` script.rb`.
So far what I have is just a couple of scripts (separate files) where I have no classes, just a couple of methods. The processing of taking user input and running those methods is outside of any functions. I see that this model may be not right.
My question is, what should I do now to keep every script self contained but also to allow other scripts to use it? Should every script just contain a class with a main method that I would run object.main?
Or maybe my approach of writing a simple scripts, no classes is also good?
If I start a new script, should I always go the objective way?
When I write a one off script, I often wrap it in a class. You've pointed out some advantages of doing this including reuse and cleaner documentation.
I find that there are several levels of polish for scripts depending on how they are going to be used. If the script is run once and never used again, I may not wrap it in a class. If it's important (taking backups of production systems), it's probably worth putting it in full gem form and writing tests. Somewhere in the middle is the single purpose class. Generally this means you're taking the code that's not in a method and putting it in the class constructor.
This:
#!ruby
def amethod(i)
i+1
end
ARGF.each do |l|
if l.chomp.to_i > 0
puts amethod(l.chomp.to_i)
end
end
Becomes:
#!ruby
class OneAdder
def amethod(i)
i+1
end
def initialize
ARGF.each do |l|
if l.chomp.to_i > 0
puts amethod(l.chomp.to_i)
end
end
end
end
OneAdder.new
I have 2 files which should be run in order. I create run.rb file:
files =[
'./file-name-1.rb',
'./file-name-2.rb',
]
files.each do |file|
require file
end
And run it. Are there more correct methods of solving this problem?
Since it is file-name-2.rb that depends on file-name-1.rb, then it should be the one to require "file-name-1.rb". It should not be run.rb's job to know what another file's dependencies are. The correct way to solve this, then, is:
file-name-2.rb
require "file-name-1.rb"
# ...
run.rb
require "file-name-2.rb
# ....
And, as Frederick suggests in the comments above, it's unorthodox for a file to do work other than declaring constants (classes, modules) and/or methods at the time it's required. Instead, it should define methods to do that work, and then other files that require it can invoke those methods. This way you always know exactly when the work will be done, even if your application has a complex dependency structure.
I am currently working through the Well Grounded Rubyist. Great book so far. I am stuck on something I don't quite get with ruby. I have two files
In ModuleTester.rb
class ModuleTester
include MyFirstModule
end
mt = ModuleTester.new
mt.say_hello
In MyFirstModule.rb
module MyFirstModule
def say_hello
puts "hello"
end
end
When I run 'ruby ModuleTester.rb', I get the following message:
ModuleTester.rb:2:in <class:ModuleTester>': uninitialized constant ModuleTester::MyFirstModule (NameError)
from ModuleTester.rb:1:in'
From what I have found online, the current directory isn't in the the namespace, so it can't see the file. But, the include statement doesn't take a string to let me give the path. Since the include statement and require statements do different things, I am absolutely lost
as to how to get the include statement to recognize the module. I looked through other questions, but they all seem to be using the require statement. Any hints are greatly appreciated.
You use require to load a file, not include. :-)
First, you have to require the file containing the module you want to include. Then you can include the module.
If you're using Rails, it has some magic to automagically require the right file first. But otherwise, you have to do it yourself.
You need to require the file before you can use types defined in it. *
# my_first_module.rb
module MyFirstModule
def say_hello
puts 'hello'
end
end
Note the require at the beginning of the following:
# module_tester.rb
require 'my_first_module'
class ModuleTester
include MyFirstModule
end
mt = ModuleTester.new
mt.say_hello
The require method actually loads and executes the script specified, using the Ruby VM's load path ($: or $LOAD_PATH) to find it when the argument is not an absolute path.
The include method, on the other hand actually mixes in a Module's methods into the current class. It's closely related to extend. The Well Grounded Rubyist does a great job of covering all this, though, so I encourage you to continue plugging through it.
See the #require, #include and #extend docs for more information.
* Things work a bit differently when using Rubygems and/or Bundler, but getting into those details is likely to confuse you more than it's worth at this point.