I'm not sure I've seen this addressed, but I am wondering what is the best way to do multiple requires in a ruby script. I have come up with a couple rudimentary examples which I will outline below, but I'm not sure if there is a best practice for this -- my search results have come back with nothing.
0) Bunch of includes & exceptions (I'll leave the rescue out)
require 'rubygems'
require 'builder'
1) String array
torequire = ['rubygems', 'builder']
begin
torequire.each do |req|
require req
rescue LoadError => e
# Not sure if this is great either
puts "Missing required gem: " + e.message.split[-1]
exit
end
2) ??
Is there a large problem created from loading them all from a string array? You could specify version requirements or locations similarly, I'm just wondering if there is a problem with doing it this way.
The plain way is the best way.
You could do this, but it trades clarity for cleverness--a poor bargain:
[
'rubygems',
'rack',
'rails'
].each(&method(:require))
Skip the "rescue" with the fancy error message. Everyone knows what it means when a require throws a stack trace.
If you want to make it easier for someone using your program to have the required gems installed, check out bundler.
All of the ruby scripts i have seen just list one require per line like you have first.
require 'rubygems'
require 'rack'
require 'rails'
In the first one it is clear what you're doing.
In the second it requires someone to decode what you're doing.
It seems a bit whimsical to force everybody to decode what you're doing so you can save a few lines of typing (and that only if you're using a whole lot of libraries in one source file which is a bit of code smell in and of itself). Remember that code is read an order of magnitude or three times as often as it is written. If it's a choice between easy writing or easy reading, the reading should win out.
%w(rubygems rack rails).each { |gem| require gem }
or, with a reusable function:
def require_all(gems) ; gems.each { |gem| require gem } ; end
...
require_all %w(rubygems rack rails)
Neither is popular Ruby style (especially a one-liner function), but Ruby embraces TIMTOWTDI, so use them if they work for you.
This isn't the best, but if you do:
def require_all(*gems)
g = *gems
g.each {|gem| require gem }
end
Alternatively add this one-liner to the beginning of your code:
def require_all(*gems); g = *gems; g.each { |gem| require gem }; end
You can just pass multiple gems to require_all; e.g.
require_all 'rack', 'bundler', 'rails'
And so on.
Got the idea from the above answer!
Related
I am a newbie to ruby. I am trying to delete keys which are passwords from the hash while printing the hash, with/without modifying the original hash
request = {"name"=>"test-2",
"dns_zone_status"=>"valid",
"certificate_status"=>"valid",
"db_password"=>"GS*8qLiU",
"af_pass"=>"rk*pp2",
"master_password"=>"sfvrere",
"db_user"=>"testuser2"}
puts "request : #{request}"
puts "request : #{request.except("db_password","af_pass","master_password")}"
The first puts print the whole hash and the 2nd one errors undefined method 'except' for #<Hash:0x00000001dbcd00> (NoMethodError)
Use Hash#reject, which is non-destructive and returns a hash.
puts "request : #{
request.reject do |k,_|
["db_password","af_pass","master_password"].include?(k)
end
}"
#request : {"name"=>"test-2", "dns_zone_status"=>"valid", "certificate_status"=>"valid", "db_user"=>"testuser2"}
As is commonly done, I've used an underscore for the block variable holding the value associated with the key k to tell the reader that it is not used in the block calculation.
Instead of having to bring all of ActiveSupport in as a dependency (which is the gem implementing Hash#except, if you don't need it in other ways you can just inline this tiny method as:
puts "request : #{request.slice(*request.keys - ["db_password","af_pass","master_password"])}"
The Hash#except method actually comes from ActiveSupport, which is loaded by default in Rails but not in standalone Ruby.
However, that's easily remedied, all you have to is add the activesupport gem and one of the following requires:
# require everything in active support, the easy/lazy option
# this is what rails does and it's probably fine to do
# unless you really, really care about how much memory you use
require 'active_support/all'
# require only the hash extensions
require 'active_support/core_ext/hash'
# require only this one specific method
require 'active_support/core_ext/hash/except'
Note that the name of the gem (activesupport) and the library you require (active_support) are indeed named differently, which can be a little tricky to remember.
In ruby code, how would I check what external libraries are loaded? For example,
require 'some-library'
if is-loaded?('some-library')
puts "this will run"
end
or
# require 'some-library' Don't load it in here
if is-loaded?('some-library')
puts "this will not run"
end
Is there a way to do this?
Note on why I need this:
I'm working on boom, and on windows, it will try to include 'Win32/Console/ANSI', to enable ANSI color codes like \e[36m. What I'm trying to do is if the system is windows and 'Win32/Console/ANSI' is not loaded, it would append the color codes, so the color codes are not outputted. Here is the file.
Most libraries will typically define a top-level constant. The usual thing to do is to check whether that constant is defined.
> defined?(CSV)
#=> nil
> require "csv"
#=> true
> defined?(CSV)
#=> "constant"
> puts "loaded!" if defined?(CSV)
loaded!
#=> nil
require will throw a LoadError if it can't find the library you are trying to load. So you can check it like this
begin
require 'some-library'
puts 'This will run.'
rescue LoadError
puts 'This will not run'
# error handling code here
end
If you want to safely try requiring a gem/library that may or may not be available, use something like this:
begin
require 'securerandom'
rescue LoadError
# We just won't get securerandom
end
This works even if the gem in question has already been required. In that scenario the require statement will do nothing and the rescue block will never execute.
If you are just interested in whether or not a gem/library has already been loaded, check to see if one of its constants is present. I do something like this to dynamically load additional functionality if ActiveSupport is loaded:
if defined?(ActiveSupport)
require "active_support/cache/redis_store"
end
You can also use the opposite to load a compatibility layer if the gem/library is NOT present. For example, I use some Hash methods that don't exist in Ruby's core Hash implementation, but are added by ActiveSupport. So, I define those methods when my gem runs in an environment where ActiveSupport doesn't exist.
require 'core_ext/hash' unless defined?(ActiveSupport)
Require Library Unless Already Loaded
For simplicity, here's how you load a library unless it's already loaded:
require 'RMagick' unless defined?(Magick)
try this :
def loaded?(name)
r = Regexp.new("#{name}.rb$")
$LOADED_FEATURES.select{|t| t.match(r) }.any?
end
Be sure of the name of your module (search here $LOADED_FEATURES).
It seems that I cannot find much documentation on Minitest/spec so I was wondering if somebody could help me figure out how to do what I need to do. Basically I want to run tests on all my classes and modules to make sure they 1.) Output the right value type if static or 2.) In the case of to_symbols all keys are symbols. Here is what I tried so far:
What I assume the Gherkin would look like:
Given binns
When the version method is called
then the return should be a float
and version should be a method or constant
What I assumed it would be with minitest/spec:
require 'minitest/autorun'
require 'minitest/spec'
require 'binns'
given Binns do
when "the version method is called" do
then "the return should be a float" do
# Do work
end
end
end
But I get:
syntax error, unexpected keyword_when (SyntaxError)
when "the version method is called" do
^
Note: I am also open to other suggestions for testing (I don't know much about cucumber and heard it was hefty) or if somebody has a book suggestion, please do tell I've been looking for a good book on Ruby Unit Testing.
MiniTest/Spec uses Rspec-style syntax: desc, it, before, after...
require 'minitest/autorun'
require 'minitest/spec'
require 'binns'
desc Binns do
it "should return a float when the version method is called" do
# Do work
end
end
If it'd make the transition easier for you, you could alias the "desc" method to "given" and "it" method to "when".
Good tutorial from Peter Cooper here.
I want to truncate #inspect output in irb (a large output must be cropped to MAX_LEN).
Currently, I override :inspect, :to_s methods for all specific objects.
Is there are other solution?
change $stdout ?
other?
For a clean solution, gem install hirb. hirb pages irb's returned values if they get too long.
If you want to monkeypatch irb:
module IRB
class Irb
def output_value
#context.last_value.to_s.slice(0, MAX_LEN)
end
end
end
I don't recommend this because it's a hack and breaks any time gems like ap and hirb are required.
Instead of monkeypatching irb, I'd recommend trying ripl, an irb alternative that is meant to extended.
The above as a ripl plugin would be:
require 'ripl'
module Ripl::SlicedInspect
def format_result(result)
result_prompt + result.inspect.slice(MAX_LEN)
end
end
Ripl::Shell.send :include, Ripl::SlicedInspect
With this plugin, you could require it as needed or add to your ~/.riplrc if you want to always use it.
Your solution is good.
It involves no dark magic, which might make the code less understandable and error-prone.
If you're just in IRB - you could define a monkeypatch in irb itself and or load a file that monkeypatches inspect via 'load'. This way you keep it out of your core codebase but you still get the functionality you need w/o having to override inspect in every class you wish to inspect....
If it's because you have a nested hash or something that's hard to decipher, try awesome_print. You can make it the default output formatter in irb by placing the following in your .irbrc:
require 'ap'
module IRB
class Irb
def output_value
ap #context.last_value
end
end
end
This makes objects with lots of data easy to decipher in IRB.
Even if you don't use awesome_print, you can truncate output using this same technique so you don't have to override to_s in your code.
For rails 3.1.1+, place the code below in helpers/irb_helper.rb
module IRB
class Irb
MAX_LEN = 10000
def output_value
if (#context.inspect_last_value.length > MAX_LEN)
printf #context.return_format, "#{#context.inspect_last_value[0..MAX_LEN]} <- Truncated"
else
printf #context.return_format, #context.inspect_last_value
end
end
end
end
If you'd like to customize your output more, check irb's source at https://github.com/Ruby/Ruby/blob/trunk/lib/irb.rb
I sometimes modify the objects themselves (via a module called BoringInspect which I include into the relevant classes) so that exception messages are also manageable.
(sorry I should have been clearer with the code the first time I posted this. Hope this makes sense)
File "size_specification.rb"
class SizeSpecification
def fits?
end
end
File "some_module.rb"
require 'size_specification'
module SomeModule
def self.sizes
YAML.load_file(File.dirname(__FILE__) + '/size_specification_data.yml')
end
end
File "size_specification_data.yml
---
- !ruby/object:SizeSpecification
height: 250
width: 300
Then when I call
SomeModule.sizes.first.fits?
I get an exception because "sizes" are Object's not SizeSpecification's so they don't have a "fits" function.
Are your settings and ruby installation ok? I created those 3 files and wrote what follows in "test.rb"
require 'yaml'
require "some_module"
SomeModule.sizes.first.fits?
Then I ran it.
$ ruby --version
ruby 1.8.6 (2008-06-20 patchlevel 230) [i486-linux]
$ ruby -w test.rb
$
No errors!
On second reading I'm a little confused, you seem to want to mix the class into module, which is porbably not so advisable. Also is the YAML supposed to load an array of the SizeSpecifications?
It appears to be that you're not mixing the Module into your class. If I run the test in irb then the require throws a LoadError. So I assume you've put two files together, if not dump it.
Normally you'd write the functionality in the module, then mix that into the class. so you may modify your code like this:
class SizeSpecification
include SomeModule
def fits?
end
end
Which will allow you to then say:
SizeSpecification::SomeModule.sizes
I think you should also be able to say:
SizeSpecification.sizes
However that requires you to take the self off the prefix of the sizes method definition.
Does that help?
The question code got me a little confused.
In general with Ruby, if that happens it's a good sign that I am trying to do things the wrong way.
It might be better to ask a question related to your actual intended outcome, rather than the specifics of a particular 'attack' on your problem. They we can say 'nonono, don't do that, do THIS' or 'ahhhhh, now I understand what you wanna do'