Where is the ruby module self.included and self.extended behaviour documented? - ruby

I was looking at the ruby mixin blog post, and it says that when a module is included in a class its self.included() method is called.
My question is, where is this behaviour officially documented? I can't seem to locate it on the ruby-docs.org website or the pickaxe.

While it's not on Ruby Doc for some reason, included actually is documented. Running ri Module.included in the terminal provides this:
included( othermod )
Callback invoked whenever the receiver is included in another module
or class. This should be used in preference to Module.append_features
if your code wants to perform some action when a module is included in
another.
module A
def A.included(mod)
puts "#{self} included in #{mod}"
end
end
module Enumerable
include A
end
This documentation can be found in the Ruby source in object.c. Sadly, Module.extended is not documented.

I suspect it's not on the RubyDoc website because it's a private method, and private methods aren't currently displayed.
People are aware of this issue, but they haven't yet worked out how to handle methods that are private even though they aren't implementation details.
I've created a bug report at http://bugs.ruby-lang.org/issues/6381

seems only public methods are documented

Both are documented on page 556 of the second edition of pickaxe (covering Ruby 1.8). The documentation there looks just like the result of ri Module.included that Andrew Marshall posted, so I suspect that section of the book was automatically generated. If it's been dropped from later editions of pickaxe, then it might be a result of the same bug that keeps it from showing up on ruby-doc.org.

Related

undefined local variable or method for extended module

NOTE: the question was edited to reflect the issue.
i would like to work with knife-api rubygem. enclosed a snippet of my code
require 'chef'
require 'chef/knife'
require 'knife/api'
module X
module Y
module Z
include Chef::Knife::API
def self.foo
resp = knife_capture :search, ['*:*']
puts resp
end
end
end
end
when X::Y::Z.foo is called, it returns
gems/knife-api-0.1.7/lib/knife/api.rb:41:in `ensure in knife_capture': undefined local variable or method `revert_io_channels' for X::Y::Z (NameError)
it appears that he enclosing scope functions (Chef::Knife within knife-api) are inaccessible within X::Y::Z.foo.
how should i make this work?
In a complete non-answer, do not use the knife-api gem. It should not exist. The correct gem to use if you want to access Chef API data from Ruby code is chef-api (I know, we're real creative with names). If you want to do something very small, check out the knife exec command which just exposes the raw Chef object API (not as refined as chef-api, but built in).
This gem is a fork of another project that is no longer maintained. Looking at the gem code, it appears there were several issues introduced to the latest version (0.1.7) through some bad refactoring of the original code. That version was released a year ago and it hasn't had any commits since. The repo also does not accept issue tickets, and it has no tests. If you must use this gem, I would try a pessimistic constraint gem 'knife-api', '< 0.1.7' and see if that works. However it might be a better idea to skip it entirely. I made an attempt to fix the issues and submit a PR. You can also try pulling the gem from my forked repo https://github.com/msimonborg/knife-api

Ruby Gems Documentation

I'm just trying to understand how to use particular ruby gems. For example, take this reddit gem. It says to have this code to start:
require 'snoo'
# Create a new instance of the client
reddit = Snoo::Client.new
# Log into reddit
reddit.log_in 'Username', 'Password'
# Send a private message to me (Paradox!)
reddit.send_pm 'Paradox', 'Snoo rubygem rocks!', "Hey Paradox, I'm trying your Snoo rubygem out and it rocks. Thanks for providing such an awesome thing!"
# Log back out of reddit
reddit.log_out
Great but in the documentation you can see that the Client class doesn't have very many exciting functions. The exciting functions are in the Account class but there is no way to get to it...because if I try something like this
reddit = Snoo::Account.new
I get this error:
`initialize': undefined method `new' for Snoo::Account:Module (NoMethodError)
Okay so there's no new method but how do I make an Account object and use its functions like log_in?
Snoo::Account is a Ruby Module, and has been mixed in to Snoo::Client already by the gem. All the functions of Snoo::Account are already available to you on the reddit object.
The synopsis documentation in the readme doesn't make this very clear. But otherwise the documentation on the gem looks good to me.
Taking a short look at the source code on github makes me believe this is a fault in the documentation, as client clearly includes the functionality of many other modules, including the Account module you would like to access. In your example code, try the following methods to confirm it for yourself:
reddit.methods.sort
reddit.is_a? Snoo::Account
I assume the documentation software didn't catch the includes as they were executed using a block.

Testing a ruby class without the required module files

I'm working on a project in Ruby on Rails. We have a controller action that uses a module within a gem. This gem isn't finished yet and it isn't on the file system.
I was told to mock the module in order to test the controller. Is there a way to test this without the actual gem? Would mocking the 'require' calls work?
We are currently using Mocha for Mocking and Stubbing.
There is a way to mock the imports in python. Maybe there is a similar answer to mocking the requires in ruby.
How to mock an import
Or please let me know what would be the best way to handle this.
Update: The person who told me to mock it, suggested adding a stub file, but that would require adding test code to the controller and I don't want to do that.
Update 2: The controller uses methods declared in the Module.
If you are writing tests to mock the method calls, they would fail. For example,
controller.should_receive(:method_in_non_existent_module).with(args) #=> errors
In a correct Red->Green TDD scenario , this is alright because the next step would be to require the gem/file, include the module and add the method call in the controller and make the test pass. But you'll not be able to make the tests pass since you can't require the file because it doesn't exist yet.
May be the developer who asked you to mock the method meant to do so not in your tests, but in your actual code. For example, he's writing a gem 'dongle-jokes' which has a method that gets the most popular dongle joke from the most recent tech conference. He doesn't want the gem to be a blocker for you to finish the controller and the views so he asks you to use a dummy interface that spits out a dummy response.
Write the tests that fail
Add a file lib/dongle-jokes.rb
Add the following to that file.
module DongleJokes
def joke
"Dongle jokes aren't funny!"
end
end
Require the file and include the module, use the method in the controller.
The test should pass now. You can remove lib/dongle-jokes.rb when you start using the actual gem.
If you're working in Rails you shouldn't need to add a require to the controller anyway, as when you add the gem to your gemfile it will be required automatically on Rails startup.
What your colleague most likely meant was that you should stub the module itself. Are you using rspec for your tests? If so you should be able to use stub_const. Let's say the module is called Payments. You can then write test code like the following:
before do
stub_const("Payments", stub)
Payments.stub(process: "payments successful")
end

Accessing the Evernote API through Ruby

I have a bunch of notes in Evernote which I would like to access in a Rubyish way (instead of only using the web interface). I thought I'd use this gem (https://github.com/cgs/evernote), which is "...a high level wrapper around Evernote's Thrift-generated ruby code. It bundles up Evernote's thrift-generated code and creates some simple wrapper classes."
I got a developer key, and the sample code here (https://github.com/cgs/evernote/blob/master/example.rb) worked, giving me the correct name for my sandbox notebook.
However, I don't understand what to do next. By "simple wrapper classes" I was expecting the Evernote::EDAM::Type::Notebook object to be some Enumerable object that I could use blocks to query. I dunno, something like
notebook.select {|note| note.tags == 'foo'}
But when I do the notebook.TAB TAB trick in IRB to look at available methods, there is nothing like that. The author of the gem refers users to Evernote API at http://www.evernote.com/about/developer/api/ref/ , and I can't make heads or tails of the thing. Am I out of luck until I fully understand what things like THRIFT means, or is there a simple listing of methods somewhere that I'm failing to look?
You shouldn't have to learn anything about Thrift. The data model wrapper classes (Note, Notebook, Tag, etc) are basically dumb structs; the methods to exercise them are on the endpoint classes, UserStore and NoteStore. For example, to get a list of Notebooks, you'd call NoteStore.listNotebooks. You can see some examples in the SDK under ruby/sample.
I've run into this issue recently, to use Ruby accessing the Evernote API. And here is the list which may help:
Official Ruby Demo
Evernote Developer Guide
Evernote API: All declarations
ENML
And I wrote a demo to make it more specific and straight.
Evernote API Ruby demo

What does the World() method do in ruby?

I'd like to know what does the following line do:
World(::Cucumber::Rails::Capybara::SelectDatesAndTimes)
Because I'm getting
uninitialized constant Cucumber::Rails::Capybara::SelectDatesAndTimes::XPath (NameError)
And I don't understand what it is supposed to do to tell what's wrong :-)
EDIT: I gisted my Gemfile: https://gist.github.com/822480 and my gem list on windows vista 32-bit (https://gist.github.com/822483) and ubuntu maverick 32-bit https://gist.github.com/822491. Both are running ruby 1.8.7. Notice that I'm using this fork of cucumber-rails: https://github.com/johnf/cucumber-rails because my ultimate goal is to get these datetime selectors to work with capybara.
I also found that on Linux I get another error message:
Unable to find '#<XPath::Union:0xb6e078b8>' (Capybara::ElementNotFound)
The World() method isn't one from Ruby, it's one specifically from Cucumber, regrettably they haven't even documented it.
http://rubydoc.info/github/aslakhellesoy/cucumber-rails/master/Cucumber/Rails/World:initialize
In this case, it looks like something it missing from your Environment, maybe Caprybara, please give more info, and share your Ruby/Rails/Cucumber/Bundler/etc versions, and your Gemfile.
World is just an instance of Object that you can use in every step definition, its like a library that you expose without the need to import (or require in every step definition file).
see more at: https://github.com/cucumber/cucumber/wiki/Configuring-the-Scenario-Execution-Context-(World)
(Note that I'm still learning, so this may be wrong.)
A world-level method involves multiple objects versus a class- or object-specific method.
If you are having an issue with calling a world method, then check to see if the world method is specifying an object that can't be found.

Resources