Can you require multiple packages on the same line? - ruby

I have this in my code:
require 'uri'
require 'net/http'
require 'csv'
Which isn't super compact or DRY. Can you put multiple require's on the same line?
Something like this:
require 'uri', 'net/http', 'csv'

I don't think so. Reading the Kernel#require it only accepts one filename as argument.
But you can do something like (don't know if this will feel you better).
%w[uri net/http csv].each { |f| require f }
It's common to perform a runtime require for relative paths like reading files from folder for example.

Can you put multiple require's on the same line?
Yes, you can. In fact, the answer to the question "Can you do X in one line" is always "Yes", since newlines are never needed in Ruby.
require 'uri'; require 'net/http'; require 'csv'

Related

Parse Ruby file for comments

I want something that can parse a ruby file to give me the file positions of comments. Ranked by desirability:
Ideally, there would be some command-line arg I could pass to "ruby" since of course "ruby" would know. But there doesn't seem to be one for this?
Does anyone know if/where in "ruby" I could hook in and use its methods to know where the comments are?
Some well-known regular expression?
Thanks!
Found: https://github.com/ruby/ruby/tree/trunk/ext/ripper
Example:
require 'ripper'
require 'pp'
class CommentRipper < Ripper::SexpBuilder
def on_comment(token)
super.tap { |result| pp result }
end
end
contents = File.read("file.rb")
pp CommentRipper.new(contents).parse
Helped me understand Ripper better: http://svenfuchs.com/2009/7/5/using-ruby-1-9-ripper

Writing unicode json in Ruby

In Ruby 2.0.0, I want to write an array to json:
require 'json'
File.open('test.json', 'w') do |f2|
f2.puts ["£2M worth of wine"].to_json
end
This gives writes a file looking like this:
["£2M worth of wine"]
Obviously, not what I am looking for. Is this a bug in to_json? How can I make it work?
You might want to force each element in the array to be encoded UTF-8 before calling to_json
e.g:
["£2M worth of wine"].map { |str| str.encode("utf-8") }.to_json

How do you check if a library/ruby-gem has been loaded?

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).

What's the best way to do multiple requires in Ruby?

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!

Why don't modules always honor 'require' in ruby?

(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'

Resources