Ruby separate large source files into multiple files - ruby

I am writing a Ruby script which was supposed to be a small thing but has grown quite large, way to large to have everything crammed into one source file. So I am trying to separate the project into different files. I have four classes and I want to put each in its own separate source file.
What I did:
I moved all of the classes into their own files so now I have this
proj/GoogleChart.rb
proj/BarChart.rb
proj/PieChart.rb
proj/GroupedBarChart.rb
Now that they are in other files I am getting uninitialized constant GoogleChart (NameError) in all of my subclasses on the line where I inherit from GoogleChart, i.e.
require 'GoogleChart'
BarChart < GoogleChart
Can anyone tell me what is wrong?
Thanks
EDIT
Using ruby version 1.8.4
Also I have tried using the absolute path:
require 'C:/Documents and Settings/proj/GoogleChart.rb' and this is still producing a NameError

In Ruby 1.8.x, the . is part of your load path. So you should at least try to debug that by including something like:
puts $:
require 'GoogleChart'
class BarChart < GoogleChart
end
and load that in an IRB session:
Open the session in your directory proj.
Enter there require 'BarChart'
Look at the result.
For me it is:
c:\apps\ruby\test\proj>irb
irb(main):001:0> require 'BarChart'
C:/Users/mliebelt/.pik/rubies/Ruby-187-p334/lib/ruby/site_ruby/1.8
C:/Users/mliebelt/.pik/rubies/Ruby-187-p334/lib/ruby/site_ruby/1.8/i386-msvcrt
C:/Users/mliebelt/.pik/rubies/Ruby-187-p334/lib/ruby/site_ruby
C:/Users/mliebelt/.pik/rubies/Ruby-187-p334/lib/ruby/vendor_ruby/1.8
C:/Users/mliebelt/.pik/rubies/Ruby-187-p334/lib/ruby/vendor_ruby/1.8/i386-msvcrt
C:/Users/mliebelt/.pik/rubies/Ruby-187-p334/lib/ruby/vendor_ruby
C:/Users/mliebelt/.pik/rubies/Ruby-187-p334/lib/ruby/1.8
C:/Users/mliebelt/.pik/rubies/Ruby-187-p334/lib/ruby/1.8/i386-mingw32
.
=> true
So the require is successful for me, and the . is part of the path (as it should). As you can see, I am working with Ruby 1.8.7, I don't know if anything has changed since 1.8.4 that is relevant here.
So please describe exactly how you run your file:
Have you opened a shell to run the file?
What is the current working directory of that shell?
Do you run by double-clicking it?
It only works when you are in your proj directory and run there (with ruby in your shell path) ruby BarChart.rb.

Related

Ruby: Require Fails To Import - Need To Set Root Directory

Forgive my inexperience with Ruby, but I am unable to run a script within a third-party project with the following structure:
˅ alpha
˅ lib
˅ bravo
golf.rb
˅ charlie
˃ delta
˅ echo
foxtrot.rb
require "charlie/delta/echo/__init"
__init.rb
require "bravo/golf"
What should my command-line be to run the script, 'foxtrot.rb', as the following generates an error:
ruby "c:\arby\lib\bravo\charlie\delta\echo\foxtrot.rb"
"'require': cannot load such file -- charlie/delta/echo/__init (LoadError)"
If this is the code inside of __init.rb, it won't work.
require "charlie/delta/echo/__init"
__init.rb
require "bravo/golf"
require tells ruby to load the code inside a ruby file. In order for it to work, the files need to be organized correctly. You can also use require_relative but they still need a relative path from the file calling them. See What is the difference between require_relative and require in Ruby?

Cannot open file ruby.png in Gosu using Learn Game Programming with Ruby

I'm using the Learn Game Programming with Ruby book and I'm trying to just execute the sample code.
I get the following error, using the sample code.
❯ ruby WhackARuby/WhackARuby_1/whack_a_ruby.rb code
/Users/noahclark/.rvm/gems/ruby-2.2.1/gems/gosu-0.10.4/lib/gosu/patches.rb:40:in `initialize': Cannot open file ruby.png (RuntimeError)
from /Users/noahclark/.rvm/gems/ruby-2.2.1/gems/gosuu0.10.4/lib/gosu/patches.rb:40:in `initialize'
from WhackARuby/WhackARuby_1/whack_a_ruby.rb:15:in `new'
from WhackARuby/WhackARuby_1/whack_a_ruby.rb:15:in `initialize'
from WhackARuby/WhackARuby_1/whack_a_ruby.rb:70:in `new'
from WhackARuby/WhackARuby_1/whack_a_ruby.rb:70:in `<main>'
The sample code looks like this:
require 'gosu'
class WhackARuby < Gosu::Window
def initialize
super(800, 600)
self.caption = 'Whack the Ruby!'
#image = Gosu::Image.new('ruby.png')
end
end
Any thoughts on what could be going on here? I've tried changing the offending line to #image = Gosu::Image.new('./ruby.png') for example and that didn't help.
I doubt this is the cause, but my ruby version is ruby 2.2.1p85 (2015-02-26 revision 49769) [x86_64-darwin14]
EDIT includes file path:
Invariably the problem is because the file doesn't exist where you think it is.
There are many ways to reference a file. The File documentation has expand_path, realpath, absolute_path, all of which make it easy to reference a file based on an absolute or relative path, and relative to the currently running file, application or a particular directory. How to use them is covered in their examples.
It's important to make sure you know what directory the code considers it's current-working-directory, and/or where the file is. The first is important when using a relative path, and the second is if you don't want to care about your current path and know that the file ALWAYS exists in a certain place.
And, then there's also the case when the file's name is different than what you think it is, or it doesn't even exist.
In my case the solution was using a more explicit filepath:
Gosu::Image.new("#{__dir__}/ruby.png")

Creating Ruby Main (command line utility) program with multiple files

I am trying to use the main gem for making command line utilities. This was presented in a recent Ruby Rogues podcast.
If I put all the code in one file and require that file, then rspec gives me an error, as the main dsl regards rpsec as a command line invocation of the main utility.
I can break out a method into a new file and have rspec require that file. Suppose you have this program, but want to put the do_something method in a separate file to test with rspec:
require 'main'
def do_something(foo)
puts "foo is #{foo}"
end
Main {
argument('foo'){
required # this is the default
cast :int # value cast to Fixnum
validate{|foo| foo == 42} # raises error in failure case
description 'the foo param' # shown in --help
}
do_something(arguments['foo'].value)
}
What is the convenient way to distribute/deploy a ruby command line program with multiple files? Maybe create a gem?
You are on the right track for testing - basically you want your "logic" in separate files so you can unit test them. You can then use something like Aruba to do an integration test.
With multiple files, your best bet is to distribute it as a RubyGem. There's lots of resources out there, but the gist of it is:
Put your executable in bin
Put your files in lib/YOUR_APP/whatever.rb where "YOUR_APP" is the name of your app. I'd also recommend namespacing your classes with modules named for your app
In your executable, require the files in lib as if lib were in the load path
In your gemspec, make sure to indicate what your bin files are and what your lib files are (if you generate it with bundle gem and are using git, you should be good to go)
This way, your app will have access to the files in lib at runtime, when installed with RubyGems. In development, you will need to either do bundle exec bin/my_app or RUBYLIB=lib bin/my_app. Point is, RubyGems takes care of the load path at runtime, but not at development time.

Call one Ruby Script from Another

I am having a perplexing problem. I want to call one ruby script from another.
With this in mind, I create a testscript.rb and executed it, it contains this code,
require './paypal.rb'
puts paypal['L_AMT0']
This code returns a number, which is my paypal balance. It relies on a paypal.rb file which uses the ruby-paypal gem. When I do ruby testscript.rb I get the output of my paypal balance, which means it is working properly. This tells me that my method for calling one RB from another is okay, since, in the above scenario, testscript.rb is getting a variable that is returned from paypal.rb.
Using this same logic, I inserted the above code into another program which is called SiriProxy. It is a ruby program. I need it to get my paypal balance.
So Inside that program, I did a require paypal.rb, it failed because it could not find it, so I set an absolute path in require which fixed it.
However, when SiriProxy (the other ruby rb giving me an issue) trys to run puts paypal['L_AMT0'] it results in an error and ends the program.
This is the error,
[Info - Plugin Manager] Say: Checking Paypal Balance
/home/siriproxy/.rvm/gems/ruby-1.9.3-p194#SiriProxy/gems/siriproxy-0.3.0/plugins/siriproxy-example/lib/siriproxy-example.rb:47:in `block in <class:Example>': undefined local variable or method `paypal' for #<SiriProxy::Plugin::Example:0x931a228> (NameError)
from /home/siriproxy/.rvm/gems/ruby-1.9.3-p194#SiriProxy/bundler/gems/cora-1edcfb9073d5/lib/cora/plugin.rb:47:in `instance_exec'
from /home/siriproxy/.rvm/gems/ruby-1.9.3-p194#SiriProxy/bundler/gems/cora-1edcfb9073d5/lib/cora/plugin.rb:47:in `block (2 levels) in process'
In the above output it appears the issue is it does not understand "paypal", as seen here:
undefined local variable or method `paypal'
However, I do not understand why, since in testscript.rb I do the exact same thing and it works.
Can anyone help? Thank you.
Seems like #CodeGnome is right.
From the Kernel documentation:
require(name) → true or false
Loads the given name, returning true if successful and false if the
feature is already loaded.
require_relative(string) → true or false
Ruby tries to load the library named string relative to the requiring
file’s path. If the file’s path cannot be determined a LoadError is
raised. If a file is loaded true is returned and false otherwise.
Loading Files from the Current Directory
I don't know anything about your library or its internals, but it looks like your require statement may be wrong. If you want to load a file from the current directory in Ruby 1.9.3, you should use:
require_relative 'paypal'
Bundler and Gems
If it's a gem that you've installed as part of a bundle (e.g. the gem is defined in a Gemfile), then providing a path in your require statement is wrong. Instead, you need to require the bundled gem as follows:
require 'bundler/setup'
require 'paypal'

Setting up rake-pipeline for use with handlebars alongside Google App Engine

So here's what I'm attempting to do. I'm building an ember.js application, with a java backend running on GAE.
I'm using handlebars, but I want them divided up into separate files, not just all pasted into the index.html.
Via the ember.js irc I was turned on to rake-pipeline along with minispade
Along with the web filters and a custom handlebars filter I started building the assetfile. I don't know Ruby, or gem files, etc.
So I'm trying to figure out the best way to be able to compile my coffeescript/handlebars files on the fly, minispade them, but keep the individual files accessible while in dev mode so I can debug them. What makes that hard is that the rake pipeline is running on a different port than GAE. So I'm not sure exactly how to handle this. Do I make my index file in GAE point to individual files at the 9292 port (rakep) during development, but in production mode point to the fully concatenated version? I'm not sure.
So I was attempting to do that here: https://gist.github.com/1495740 by having only one section that was triggered by the 'build' flag. Not even sure if that works that way.
I know there's a lot of confusion here. Apologies, like I said I'm not even remotely familiar with the Ruby style of doing things.
Since you're not a Ruby person, here are the most reliable steps for getting a stock OSX environment set up with rake pipeline:
Step 1: Install bundler
# on OSX, using built-in Ruby
$ sudo gem install bundler --pre
Step 2: Create a Gemfile
# inside your app directory
$ bundle init
# will create a file named Gemfile in the root
Step 3: Add rake-pipeline to the Gemfile
# inside the Gemfile
gem "rake-pipeline-web-filters"
Step 4: Install your gems
$ bundle install --binstubs
Step 5: Set up Assetfile
However you were already doing it...
Step 6: Run Rake::Pipeline
# to run the preview server
$ bin/rakep
# to build your assets
$ bin/rakep build
Rake::Pipeline.build is the method that evaluates an Assetfile. You can imagine that your entire Assetfile is wrapped inside a Rake::Pipeline.build {} block; you shouldn't ever need to write one inside an Assetfile.
Some of the filters in the docs are hypothetical, most of those docs were written before there were any filters at all. A CoffeeScript compiler has been recently added, though.
As to your main question, I'm not sure there's a clean way to do it with the current rakep implementation. An Assetfile is just Ruby, though, so it's possible to hack something together that should work. Here's how I would write yours:
require "json"
require "rake-pipeline-web-filters"
require "rake-pipeline-web-filters/helpers"
class HandlebarsFilter < Rake::Pipeline::Filter
def initialize(&block)
block ||= proc { |input| input.sub(/\.handlebars$/, '.js') }
super(&block)
end
def generate_output(inputs, output)
inputs.each do |input|
output.write "return Ember.Handlebars.compile(#{input.read.to_json})"
end
end
end
# process all js, css and html files in app/assets
input "assets"
# processed files should be outputted to public
output "public"
# process all coffee files
match "**/*.coffee" do
# compile all CoffeeScript files. the output file
# for the compilation should be the input name
# with the .coffee extension replaced with .js
coffee_script
# The coffee_script helper is exactly equivalent to:
# filter Rake::Pipeline::Web::Filters::CoffeeScriptCompiler
end
match "**/*.js" do
minispade
if ENV['RAKEP_ENV'] == "production"
concat "application.js"
else
concat
end
end
match "**/*.handlebars" do
filter HandlebarsFilter
minispade
concat "templates.js"
end
The if ENV['RAKEP_ENV'] bit reads an environment variable to decide whether to concatenate your JS to a single file.
So now you can run RAKEP_ENV="production" rakep build for a concatenated build, or just rakep build for a development build.

Resources