How to have multiple gems that share the same common Ruby module? - ruby

I've written a Ruby module, common_services.rb, which contains convenience methods for interfacing with a web service; I consider it a piece of common code. Now, I would like to create two separate gems, both of which utilize the convenience methods in this module. I visualize something like this:
rubyStuff/
commonCode/
common_services.rb <-- common code lives here
gemA/
bin/
lib/ <-- gemA would like to pull in common_services to use it
gemA.gemspec
gemB/
bin/
lib/ <-- gemB would also like to pull in common_services to use it
gemB.gemspec
Each of gemA and gemB would have a reference to the common code in order to use it, for example rubyStuff/gemA/lib/gemA/main.rb might begin as:
require_relative '../../commonCode/common_services.rb'
puts CommonServices.getMessageOfTheDay()
<etc>
It's not working out too well for me, so I'm wondering if there is a better way to do this in Ruby. One problem I'm having is with packaging a gem to reference a file that is outside of its own path:
s.files = Dir['bin/**'] + Dir['lib/**/*'] + Dir['../commonCode/**']
When using the .. notation in the gemspec, and trying to install the resulting gem, produces:
ERROR: While executing gem ... (Gem::Package::PathError) installing into parent path /Users/me/.rvm/gems/ruby-2.0.0-p247/gems/commonCode/common_services.rb of /Users/me/.rvm/gems/ruby-2.0.0-p247/gems/gemA-0.0.1 is not allowed
It makes sense to me why gems are not allowed to reach outside of their own path, but I'm not sure how to resolve this issue. In Ruby, how and where should I organize Ruby code that will be used by multiple gems in my codeline, so that the multiple gems can use this common code? Am I going about reuse entirely the wrong way? Symbolic link magic?
Thanks for taking the time to read through this.

Summarizing comments above for posterity...
There are a couple things to consider here.
1. Is commonCode significant? Is it a good chunk of code, or just a few files?
2. Are gemA and gemB significant? Should each of them really be gems?
Seems like you're in either one of two situations, depending on the significance of the code you've written:
commonCode is significant enough (amount of code, complexity, logical separation from gemA and gemB) to merit its own gem? If so, definitely pull it out into its own gem. You can require gem-common in the other two. It doesn't make sense to require a plain ruby file in A and B that lives outside of those two code bases.
commonCode is too insignificant to be pulled into its own gem. If this is the case, you should consider whether or not gemA and gemB really deserve their own gems, each. If they aren't big enough or logically separate enough, maybe all three can be combined into a larger gem.

Related

ruby module structure insight

I'm new to Ruby and i'm making a Ruby package.
structure is:
eventsims (main folder)
|__lib
|__eventsims {subfolder)
| |__discrete.rb
| |__randgen.rb
| |__simevent.rb
| |version.rb
|__eventsims.rb
If i put all the codes in my three modules file (discrete, randgen and simevent) in the ["Eventsims" module inside the eventsims.rb file], it is easy but there would be up to 1000 lines of code which I don't want
Now I have a "require" lines of code inside eventsim.rb that requires all these four files in the eventsim subfolder.
I can use all the modules, no errors.
for example in the discrete.rb, a module called Discrete with a Calculate class having an expectval method:
Is this how I would be able to use the package after installing it with Rubygems
require "Eventsims"
a = Discrete::Calculate.new([1,0,4,2], [0.2, 0.4, 0.6, 1.0])
a.expectval()
and if yes, is it sensible to have it that way because so many modules I've seen will have something like:
require "eventsims"
Eventsims::someclass.new
which in my case would be
require "eventsims"
Discrete::someclass.new
I'm worried about the consistency of the required file and its namespacing. require eventsim and its different Discrete
Sorry the question is really long.
Unlike some other languages, Ruby does not tie the filesystem names to module hierarchy. If you want to have require "eventsims" provide the module Discrete, you can. Whether or not it's a good idea, it is for you to decide - Ruby is not your Mum. There are two potential pitfalls:
Gem users might get confused, and wonder how to use your gem
Someone in some other gem also defines Discrete and you have a collision.
A compromise between the two approaches (having a distinct namespace and having less to type) is to indeed have a top module EventSims, and for users to include it if they want to access the next level down directly:
# safe usage
require 'eventsims'
EventSims::Discrete::Calculate.new
# easy usage
require 'eventsims'
include EventSims
Discrete::Calculate.new
# restricted easy usage
require 'eventsims'
module MyCode
include EventSims
Discrete::Calculate.new
end
EventSims::Discrete::Calculate.new
This way, you still have namespacing, and you can get rid of it when you know there is no collision in your code. Going the other way around (having no namespacing and trying to isolate the code when a collision does happen) is significantly more difficult.

Advice on how/where to place requires in own gem

I am going through the blog Creating mountable Gem:
Its important to note that you should require your dependent gems explicitly in the root file of your gem. Say if your gem is named my_cool_gem, then you should have my_cool_gem.rb created inside lib folder. If your gem is dependent on strong_parameters, then you need to add these lines:
The author did not mention why it is required to have the dependent gems explicitly in the root file. Can some one explain why this needs to be done?
It's just cleaner. What if you had require statements in various files scattered all over your gem? It'd be a mess to easily see all the dependencies.
This statement:
Its important to note that you should require your dependent gems
explicitly in the root file of your gem.
It is not a strict statement that you have to conform to (to be fair to the author, the word is "should", not "must"). Some people prefer to take a different approach, and e.g. require dependencies only in parts of the library that use them.
However, you do need to consider:
Execution order of require statements that define symbols used elsewhere. You cannot call a DSL method that sets up instance methods for you, if the gem that provides the method has not yet been require-d
You should check that you really do require all correct the dependencies, and your gem functions correctly in projects that do not load them already.
With both of these in mind, it is often quickest and easiest to require dependencies early and and in a way that can be quickly viewed. So the advice is sound; as it was presented in a very short article, covering the statement with caveats and extra background would make the whole thing a lot less pithy.

Ruby class loading mechanism

I'm beginning with the Ruby programming language and I'm interested in understanding it in depth before I start studding the Rails framework.
I'm currently a little disappointed because everybody seams to care only about the Rails framework, and other aspects of the language are just not discussed in depth, such as its class loading mechanism.
Considering that I'm starting by doing some desktop/console experiments, I would like to better understand the following matters:
Is it a good practice to place each Ruby class in a separate Ruby file? (*.rb)
If I have, let's say .. 10 classes .. and all of them reference each other, by instantiating one another and calling each other's methods, should I add a 'require' statement in each file to state which classes are required by the class in that file? (just like we do with 'import' statements in each Java class file?)
Is there a difference in placing a 'require' statement before or after (inside) a class declaration?
What could be considered a proper Ruby program's 'entry point'? It seams to me that any .rb script will suffice, since the language doesn't have a convention like C or Java where we always need a 'main' function of method.
Is class loading considered a 'phase' in the execution of a Ruby program? Are we supposed to load all the classes that are needed by the application right at the start?
Shouldn't the interpreter itself be responsible for finding and loading classes as we run the code that needs them? By searching the paths in the $LOAD_PATH variable, like Java does with its $CLASSPATH?
Thank you.
In general terms, it's a good practice to create a separate .rb file for each Ruby class unless the classes are of a utility nature and are too trivial to warrant separation. An instance of this would be a custom Exception derived class where putting it in a separate file would be more trouble than its worth.
Tradition holds that the name of the class and the filename are related. Where the class is called ExampleClass, the file is called example_class, the "underscored" version of same. There are occasions when you'll buck this convention, but so long as you're consistent about it there shouldn't be problems. The Rails ActiveSupport auto-loader will help you out a lot if you follow convention, so a lot of people follow this practice.
Likewise, you'll want to organize your application into folders like lib and bin to separate command-line scripts from back-end libraries. The command-line scripts do not usually have a .rb extension, whereas the libraries should.
When it comes to require, this should be used sparingly. If you structure your library files correctly they can all load automatically once you've called require on the top-level one. This is done with the autoload feature.
For example, lib/example_class.rb might look like:
class ExampleClass
class SpecialException < Exception
end
autoload(:Foo, 'example_class/foo')
# ...
end
You would organize other things under separate directories or files, like lib/example_class/foo.rb which could contain:
class ExampleClass::Foo
# ...
end
You can keep chaining autoloads all the way down. This has the advantage of only loading modules that are actually referenced.
Sometimes you'll want to defer a require to somewhere inside the class implementation. This is useful if you want to avoid loading in a heavy library unless a particular feature is used, where this feature is unlikely to be used under ordinary circumstances.
For example, you might not want to load the YAML library unless you're doing some debugging:
def debug_export_to_yaml
require 'yaml'
YAML.dump(some_stuff)
end
If you look at the structure of common Ruby gems, the "entry point" is often the top-level of your library or a utility script that includes this library. So for an example ExampleLibrary, your entry point would be lib/example_library.rb which would be structured to include the rest on demand. You might also have a script bin/library_tool that would do this for you.
As for when to load things, if there's a very high chance of something getting used, load it up front to pay the price early, so called "eager loading". If there's a low chance of it getting used, load it on demand, or leave it "lazy loaded" as it's called.
Have a look at the source of some simple but popular gems to get a sense of how most people structure their applications.
I'll try to help you with the first one:
Is it a good practice to place each Ruby class in a separate Ruby file? (*.rb)
It comes down to how closely related those classes are. Let's see a few examples. Look this class: https://github.com/resque/resque/blob/master/lib/resque.rb
, it "imports" the functionality of several classes that, although they work together, they are not closely related to be bundled together.
On the other hand, take a look at this module: https://github.com/resque/resque/blob/master/lib/resque/errors.rb. It bundles 5 different classes, but these do belong together since they are all essentially representing the same.
Additionally, from a design standpoint a good rule of thump could be asking yourself, who else is using this class/ functionality (meaning which other parts of the code base needs it)?
Let's say that you want to represent a Click and WheelScroll performed by a Mouse. It would make more sense in this trivial example, that those classes be bundled together:
module ComputerPart
class Mouse; end
class WheelScroll; end
class Click; end
end
Finally, I would recommend that you peruse the code of some of these popular projects to kind of get the feeling how the community usually make these decisions.
1.) I follow this practice, but it is not necessary, you can put a bunch of classes in one file if you want.
2.) If the classes are in the same file, no, they will all be accessible when you run the script. If they are in separate files then you should require them, you can also require the entire directory that the file(self) is in.
3.)Yes, it should be at the top of the file.
4.) In ruby everything descends from the Main object, the Interpreter just handles creating it for you. If you are writing OO ruby and not just scripts, then the entry point will be the init method of the first class you call.
5.) Yes, before the program runs it loads up all the dependencies.
6.) I think it does this, all you have to do is require the proper files at the top of the files, after that you can use them as you wish without having to implicitly load them again.

How to release a gem that depends on unrelated code?

Didn't really know how to title this. First time writing a gem so not sure about the best way to do it.
I am releasing a "Graphics" Ruby gem that uses a 2D Array class that I wrote. Which of the following 2 approaches is best?
Put the 2D Array class in the gem. This is fine, but I will be updating the class and I don't want to have a complicated process of updating it in one place and then copying the files into the gem and updating it.
Release the 2D Array class as a separate gem, and have the Graphics gem depend on it. I guess bundler handles this dependency so it is easy for people to use...?
Are there any other reasons to choose one over the other? Which is the best practice?
Actually, your users don't need bundler: rubygems itself handles the dependencies of gems, and yes it will be easy for people to use.
The choice between 1 and 2 is up to you. There will be some extra overhead involved to document and maintain two separate gems. If you know for sure that the 2D array class is useful on its own and you have other places where you want to use it, making two gems is a decent idea.

Adding a directory to $LOAD_PATH (Ruby)

I have seen two commonly used techniques for adding the directory of the file currently being executed to the $LOAD_PATH (or $:). I see the advantages of doing this in case you're not working with a gem. One seems more verbose than the other, obviously, but is there a reason to go with one over the other?
The first, verbose method (could be overkill):
$LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__))) unless $LOAD_PATH.include?(File.expand_path(File.dirname(__FILE__)))
and the more straightforward, quick-and-dirty:
$:.unshift File.dirname(__FILE__)
Any reason to go with one over the other?
The Ruby load path is very commonly seen written as $: , but just because it is short, does not make it better. If you prefer clarity to cleverness, or if brevity for its own sake makes you itchy, you needn't do it just because everyone else is.
Say hello to ...
$LOAD_PATH
... and say goodbye to ...
# I don't quite understand what this is doing...
$:
I would say go with $:.unshift File.dirname(__FILE__) over the other one, simply because I've seen much more usage of it in code than the $LOAD_PATH one, and it's shorter too!
I'm not too fond on the 'quick-and-dirty' way.
Anyone new to Ruby will be pondering what $:. is.
I find this more obvious.
libdir = File.dirname(__FILE__)
$LOAD_PATH.unshift(libdir) unless $LOAD_PATH.include?(libdir)
Or if I care about having the full path...
libdir = File.expand_path(File.dirname(__FILE__))
$LOAD_PATH.unshift(libdir) unless $LOAD_PATH.include?(libdir)
UPDATE 2009/09/10
As of late I've been doing the following:
$:.unshift(File.expand_path(File.dirname(__FILE__))) unless
$:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
I've seen it in a whole bunch of different ruby projects while browsing GitHub.
Seems to be the convention?
If you type script/console in your Rails project and enter $:, you'll get an array that includes all the directories needed to load Ruby. The take-away from this little exercise is that $: is an array. That being so, you can perform functions on it like prepending other directories with the unshift method or the << operator. As you implied in your statement $: and $LOAD_PATH are the same.
The disadvantage with doing it the quick and dirty way as you mentioned is this: if you already have the directory in your boot path, it will repeat itself.
Example:
I have a plugin I created called todo. My directory is structured like so:
/---vendor
|
|---/plugins
|
|---/todo
|
|---/lib
|
|---/app
|
|---/models
|---/controllers
|
|---/rails
|
|---init.rb
In the init.rb file I entered the following code:
## In vendor/plugins/todo/rails/init.rb
%w{ models controllers models }.each do |dir|
path = File.expand_path(File.join(File.dirname(__FILE__), '../lib', 'app', dir))
$LOAD_PATH << path
ActiveSupport::Dependencies.load_paths << path
ActiveSupport::Dependencies.load_once_paths.delete(path)
end
Note how I tell the code block to perform the actions inside the block to the strings 'models', 'controllers', and 'models', where I repeat 'models'. (FYI, %w{ ... } is just another way to tell Ruby to hold an array of strings). When I run script/console, I type the following:
>> puts $:
And I type this so that it is easier to read the contents in the string. The output I get is:
...
...
./Users/Me/mySites/myRailsApp/vendor/plugins/todo/lib/app/models
./Users/Me/mySites/myRailsApp/vendor/plugins/todo/lib/app/controllers
./Users/Me/mySites/myRailsApp/vendor/plugins/todo/lib/app/models
As you can see, though this is as simple an example I could create while using a project I'm currently working on, if you're not careful the quick and dirty way will lead to repeated paths. The longer way will check for repeated paths and make sure they don't occur.
If you're an experienced Rails programmer, you probably have a very good idea of what you're doing and likely not make the mistake of repeating paths. If you're a newbie, I would go with the longer way until you understand really what you're doing.
Best I have come across for adding a dir via relative path when using Rspec. I find it verbose enough but also still a nice one liner.
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
There is a gem which will let you setup your load path with nicer and cleaner code. Check this out: https://github.com/nayyara-samuel/load-path.
It also has good documentation
My 2ยข: I like $LOAD_PATH rather than $:. I'm getting old... I've studied 92,000 languages. I find it hard to keep track of all the customs and idioms.
I've come to abhor namespace pollution.
Last, when I deal with paths, I always delete and then either append or prepend -- depending upon how I want the search to proceed. Thus, I do:
1.times do
models_dir = "#{File.expand_path(File.dirname(__FILE__))}/models"
$LOAD_PATH.delete(models_dir)
$LOAD_PATH.unshift(models_dir)
end
I know it's been a long time since this question was first asked, but I have an additional answer that I want to share.
I have several Ruby applications that were developed by another programmer over several years, and they re-use the same classes in the different applications although they might access the same database. Since this violates the DRY rule, I decided to create a class library to be shared by all of the Ruby applications. I could have put it in the main Ruby library, but that would hide custom code in the common codebase which I didn't want to do.
I had a problem where I had a name conflict between an already defined name "profile.rb", and a class I was using. This conflict wasn't a problem until I tried to create the common code library. Normally, Ruby searches application locations first, then goes to the $LOAD_PATH locations.
The application_controller.rb could not find the class I created, and threw an error on the original definition because it is not a class. Since I removed the class definition from the app/models section of the application, Ruby could not find it there and went looking for it in the Ruby paths.
So, I modified the $LOAD_PATH variable to include a path to the library directory I was using. This can be done in the environment.rb file at initialization time.
Even with the new directory added to the search path, Ruby was throwing an error because it was preferentially taking the system-defined file first. The search path in the $LOAD_PATH variable preferentially searches the Ruby paths first.
So, I needed to change the search order so that Ruby found the class in my common library before it searched the built-in libraries.
This code did it in the environment.rb file:
Rails::Initializer.run do |config|
* * * * *
path = []
path.concat($LOAD_PATH)
$LOAD_PATH.clear
$LOAD_PATH << 'C:\web\common\lib'
$LOAD_PATH << 'C:\web\common'
$LOAD_PATH.concat(path)
* * * * *
end
I don't think you can use any of the advanced coding constructs given before at this level, but it works just fine if you want to setup something at initialization time in your app. You must maintain the original order of the original $LOAD_PATH variable when it is added back to the new variable otherwise some of the main Ruby classes get lost.
In the application_controller.rb file, I simply use a
require 'profile'
require 'etc' #etc
and this loads the custom library files for the entire application, i.e., I don't have to use require commands in every controller.
For me, this was the solution I was looking for, and I thought I would add it to this answer to pass the information along.

Resources