Ideal Ruby project structure - ruby

I'm after an overview/clarification of the ideal project structure for a ruby (non-rails/merb/etc) project. I'm guessing it follows
app/
bin/ #Files for command-line execution
lib/
appname.rb
appname/ #Classes and so on
Rakefile #Running tests
README
test,spec,features/ #Whichever means of testing you go for
appname.gemspec #If it's a gem
Have I got something wrong? What parts have I missed out?

I think that is pretty much spot on. By default, Rubygems will add the lib directory to the loadpath, but you can push any directory you want onto that using the $: variable. i.e.
$:.push File.expand_path(File.dirname(__FILE__) + '/../surfcompstuff')
That means when you have say, surfer.rb in that dir, you can require "surfer" anywhere and the file will be found.
Also, as a convention, classes and singletons get a file and modules get a directory. For instance, if you had the LolCatz module and the LolCatz::Moar class that would look like:
lib/
appname.rb
lolcatz/
moar.rb
That is why there is an lib/appname folder because most libraries are in the appname namespace.
Additionally, if you try running the command newgem --simple [projectname] that'll quickly generate a scaffold for you with just the bare essentials for a Ruby project (and by extension a Ruby Gem). There are other tools which do this, I know, but newgem is pretty common. I usually get rid of the TODO file and all the script stuff.

See the following example from http://guides.rubygems.org/what-is-a-gem/
% tree freewill
freewill/
├── bin/
│ └── freewill
├── lib/
│ └── freewill.rb
├── test/
│ └── test_freewill.rb
├── README
├── Rakefile
└── freewill.gemspec

I attempt to mimic the Rails project structure because my team, which usually deals with Rails, will understand the structure better than another configuration. Convention over Configuration - bleeding over from Rails.

If you use bundler, running this command bundle gem app_name will give you the same directory structure.
If you want to use rspec instead of unit tests you can then run this command rspec --init
(Just make sure you cd app_name first)

Related

Recommended file system setup for development projects?

I just got a new computer (Mac, if relevant) and I'm in the process of downloading IDEs and other stuff intended for development. Is there a recommended pattern for setting up the file system for development?
On a different computer in the past, I just created a folder titled Development in the home directory and then all workspaces were dumped in there. There is a workspace folder for Eclipse projects and then some other folders for Xcode projects.
I searched and read this blog post that recommends the conventions for Go. Any other recommended setups?
I plan to contribute to open source projects and to have some Xcode and Java projects of my own, if any of that's relevant.
This might be primarily opinion based, but the folder structure I've settled on is based on my use cases. I generally have two ways I use code: experimenting with a language, and working on a project (and that project sometimes has multiple languages). Accordingly, I create two folder heirarchies: ~/Code/<language>/ for experimenting with a language, and ~/Git/<projectname>/ for projects.
The Code might look something like this:
Code/
├── Bash
│   └── tmp.sh
├── C
│   └── tmp.c
├── CPP
│   └── tmp.cpp
└── Python
├── multifile
│   ├── first.py
│   └── second.py
└── tmp.py
And the Git folder would look something like this:
Git/
├── CoolProject
└── Project1
├── README.md
├── doc
└── src
In the Code directory, I worry much less about structure or documentation. Once/If a project grows big or important enough to version control I place it in the Git directory where I try to follow the conventional folder hierarchy for the language, like your Go link, or this Python guide or whatever Eclipse would make for Java. I do try to have a README.md at the root level of each project so I'll know what it does and I can put it on GitHub easily.

require error in ruby gem

I'm working on a Ruby gem and I'm getting an odd error. I have previously released this gem without too much trouble. I added some methods / refactored some code and wanted to release a subsequent version (from 1.1 to 1.2).
For reference, the name of the gem is Intervallum, (the word 'interval' in Latin).
I'm getting a 'require' error that's been stumping me.
The folder tree is:
.
├── Gemfile
├── LICENSE
├── README.md
├── intervallum-[version].gem
├── intervallum.gemspec
└── lib
├── intervallum
│   ├── module.scroll.rb
│   └── module.spell.rb
└── intervallum.rb
In lib/intervallum.rb I tried Dir.glob, Dir['./lib/intervallum/*'] and require '../intervallum/lib/intervallum/module.spell.rb' and what happens for each one is:
Locally, after gem build intervallum.gemspec and gem install intervallum-[version].gem, I boot up irb and require intervallum and it works fine.
push to RubyGems
remove the local copy
install from RG
load up in irb I get load errors or it cannot find class of a helper class
I'm not sure why this keeps occurring, or if there's something that I'm missing as to why this keeps occurring but any advice would be much appreciated.
The problem is that you are not including those files in the gem when it gets packaged. Your gemspec specifies that only the lib/intervallum.rb file will be included in the gem:
s.files = ["./lib/intervallum.rb"]
Change that line to include all files in lib. It's also a good idea to include the gemspec.
s.files = Dir['lib/**/*', 'intervallum.gemspec']

RSpec raises NameErrors for code in subdirectory of /lib

I have a gem project with the following structure:
foo-bar
├── lib
│   └── foo
│   ├── bar
│   │   └── qux.rb
│   └── bar.rb
└── spec
├── spec_helper.rb
└── unit
├── baz_spec.rb
└── qux_spec.rb
In lib/foo, bar.rb defines a module Foo::Bar, and inside that, a class Foo::Bar::Baz. Inside lib/foo/bar, qux.rb defines a class Foo::Bar::Qux.
spec_helper.rb sets up RSpec and Simplecov, and finishes with require 'foo/bar'. Both baz_spec.rb and qux_spec.rb start with require 'spec_helper'.
baz_spec.rb has the specs for Foo::Bar::Baz, and it works fine. qux_spec.rb, however, which has the specs for Foo::Bar::Qux, fails with:
/Users/me/foo-bar/spec/unit/qux_spec.rb:6:in `<module:Bar>': uninitialized constant Foo::Bar::Qux (NameError)
from /Users/me/foo-bar/spec/unit/qux_spec.rb:4:in `<module:Foo>'
from /Users/me/foo-bar/spec/unit/qux_spec.rb:3:in `<top (required)>'
from /Users/me/.rvm/gems/ruby-2.2.0/gems/rspec-core-3.2.2/lib/rspec/core/configuration.rb:1226:in `load'
...
(etc.)
I've verified that it's not just a typo by moving the code for Foo::Bar::Baz out of lib/foo/bar.rb and into its own file, lib/foo/bar/baz.rb, after which baz_spec.rb also stops working.
It also doesn't seem to make a difference whether I declare the class as
class Foo::Bar::Qux
...
or as
module Foo
module Bar
class Qux
...
I'm using Ruby 2.2.0 with RSpec 3.2.2 on Mac OS X Yosemite.
Clearly there's something wrong with my requires, but as a Ruby novice I'm not seeing it. Any ideas?
you need to add foo.rb file under ./lib and add require statements for each file in order you want them to get loaded. You can look at sample gem for reference: dogeify and an article that walks you through gem creation build your first gem.
If you're using ActiveSupport a single line like this will help you:
ActiveSupport::Dependencies.autoload_paths << "./lib"
If you're now trying to use Foo::Bar::Qux, ActiveSupport will look for a file named foo/bar/qux.rb inside of the lib folder.
Solved: after taking a closer look at the other projects I was cargo-culting from, I realized I'd misunderstood require.
Unlike (apparently) its Rails equivalent, the out-of-the-box Kernel.require just loads .rb files (and extension libraries). So in the example above, require 'foo/bar' doesn't load files from the foo/bar directory, it just loads foo/bar.rb.
In order to load the files under foo/bar, including qux.rb, I had to go into bar.rb and explicitly load those files at the top of the module declaration:
module Foo
module Bar
Dir.glob(File.expand_path('../bar/*.rb', __FILE__), &method(:require))
# ...module declaration continues...
Just one of the many scripting-language-heritage pitfalls waiting for those who come to Ruby from other more heavyweight languages, I suppose.

go install creates directory os_arch - select different output directory

I have this folder structure for my fib package:
$ tree
.
└── src
└── fib
├── fib
│   └── main.go
├── fib.go
└── fib_test.go
(main.go is in package main, fib(_test).go is in package fib)
GOPATH is set to $PWD/src, GOBIN is set to $PWD/bin. When I run go install fib/fib, I get a file called fib in the directory bin (this is what I expect):
$ tree bin/
bin/
└── fib
But when I set GOOS or GOARCH, the directory in the form GOOS_GOARCH is created:
$ GOARCH=386 GOOS=windows go install fib/fib
$ tree bin/
bin/
└── windows_386
└── fib.exe
This is not what I want. I'd like to have the file fib.exe in the bin directory, not in the sub directory bin/windows_386.
(How) is this possible?
That doesn't seem possible, as illustrated in issue 6201.
GOARCH sets the kind of binary to build.
You might be cross-compiling: GOARCH might be arm.
You definitely don't want to run the arm tool on an x86 system.
The host system type is GOHOSTARCH.
To install the api tool (or any tools) you need to use
GOARCH=$(go env GOHOSTARCH) go install .../api
and then plain 'go tool' will find them.
In any case (GOARCH or GOHOSTARCH), the go command will install in a fixed location that you cannot change.
The phrase "I (don't) want" is incompatible with the go tool; the go tool works how it works. You can a) copy the file to where you want it to be after installing it with the go tool or b) compile it yourself, e.g. by invoking 6g manually (here you can specify the output). If you are unhappy with how the go tool works, just switch to a build tool of your liking, e.g. plain old Makefiles. Note that the go tool helps you there too, e.g. by invoking the compiler via go tool 6g

Fire up a web browser for a folder?

Is there an easy way to fire up a web browser for a folder?
eg.
I am in a folder that contains a website (index.html and other files) and I want to browse the site through a browser. Is there a gem that I just launch to make this folder browsable?
In this way I don't have to install nginx just for a specific folder. And when you install nginx you have to bother with configuration files and so on.
Kinda how Rails does it with:
rails server
Yes, there is... Throw the following in a file called webserver:
#!/usr/bin/env ruby
require 'webrick'
include WEBrick
server = HTTPServer.new(:Port => 3000, :DocumentRoot => Dir::pwd)
trap("INT"){ server.shutdown }
server.start
Then, perform the following (This assumes Mac OSX):
$ sudo chmod 755 webserver
$ sudo chown root:wheel webserver
$ sudo cp webserver /usr/local/bin/webserver (or somewhere in your path)
Now, just run webserver from the directory you want to use as the document root. A webserver will now be running on localhost:3000.
Hope this helps!
UPDATE
I just remembered after reading a post on Phusion Passenger 3.0 progress that there will be a passenger lite option...
Easiest way I've found is this little Python one-liner:
2.x:
python -m SimpleHTTPServer
3.x:
python -m http.server 8080
Unless you want to execute Ruby dynamically, of course. But that wasn't explicit in your question. Only static HTML.
The webbrick example works great, thanks to Brian. However, I just wanted to follow up on his update.
Assuming you have a working ruby and rubygems installed:
gem install passenger
put all files in a subdirectory called public
example project dir:
.
├── any
│   ├── old crap
│   └── that will not be on the website
└── public
├── favicon.ico
├── images
│   ├── ajax-loader-large.gif
│   ├── bg.jpg
│   ├── bg_home.jpg
│   ├── bg_nav.gif
├── index.html
├── javascripts
│   ├── jquery.liveSearch.js
├── robots.txt
└── stylesheets
├── all.css
Then run passenger start
The first time it will install a bunch of things (including nginx, but you won't have to worry about configuring it), but it should work faster after that.
And, if you have PHP >= 5.4.0, you can:
php -S localhost:8000
That's pretty easy!
Reference: http://php.net/manual/en/features.commandline.webserver.php

Resources