Dependency Injection causing both Rspec failure and IRB failure - ruby

Note: I am a Ruby and programming novice.
I have a class called JourneyLog I am trying to get a method called start to instantiate a new instance of another class, called Journey
class JourneyLog
attr_reader :journey_class
def initialize(journey_class: Journey)
#journey_class = journey_class
#journeys = []
end
def start(station)
journey_class.new(entry_station: station)
end
end
When I go into irbi get the following issue
2.2.3 :001 > require './lib/journeylog'
=> true
2.2.3 :002 > journeylog = JourneyLog.new
NameError: uninitialized constant JourneyLog::Journey
from /Users/BartJudge/Desktop/Makers_2018/oystercard-challenge/lib/journeylog.rb:4:in `initialize'
from (irb):2:in `new'
from (irb):2
from /Users/BartJudge/.rvm/rubies/ruby-2.2.3/bin/irb:15:in `<main>'
2.2.3 :003 >
I also have the following Rspec test
require 'journeylog'
describe JourneyLog do
let(:journey) { double :journey, entry_station: nil, complete?: false, fare: 1}
let(:station) { double :station }
let(:journey_class) { double :journey_class, new: journey }
describe '#start' do
it 'starts a journey' do
expect(journey_class).to receive(:new).with(entry_station: station)
subject.start(station)
end
end
end
I get the following Rspec failure;
1) JourneyLog#start starts a journey
Failure/Error: expect(journey_class).to receive(:new).with(entry_station: station)
(Double :journey_class).new({:entry_station=>#<Double :station>})
expected: 1 time with arguments: ({:entry_station=>#<Double :station>})
received: 0 times
# ./spec/jorneylog_spec.rb:9:in `block (3 levels) in <top (required)>'
I am at a total loss on what the problem is, or where to look for some answers.
I'm assuming I'm not injecting the Journey class properly, but thats as far as I can get myself.
Could someone provide some assistance?

In the journeylog.rb file you need to load the Journey class:
require 'journey' # I guess the Journey class is defined in lib/journey.rb
In the spec file you need to pass journey_class to the JourneyLog constructor:
describe JourneyLog do
subject { described_class.new(journey_class: journey_class) }
# ...

Related

undefined method 'execute' for nil:NilClass

I am making a tool in ruby which can interact with databases.
I am using amalgalite as an adapter for sqlite3.
Code:
require 'amalgalite'
# this is class RQuery
class RQuery
def db_open(db_name)
#db = Amalgalite::Database.new "#{db_name}.db"
make_class
end
def exec_this(query)
#db.execute(query)
end
def make_class
tables_list = exec_this("select name from sqlite_master where type='table'")
tables_list.each do |table|
#class_created = Object.const_set(table[0].capitalize, Class.new)
#class_created.class_eval do
define_singleton_method :first do
RQuery.new.exec_this("select * from #{table[0]} order by #{table[0]}.id ASC limit 1")
end
end
end
end
def eval_this(input)
instance_eval(input)
end
def code
print '>>'
input = gets
exit if input =~ /^q$/
puts eval_this(input)
code
end
end
Now when I am running the code everything works fine until I call table_name.first
It gives output
vbhv#fsociety ~/git/R-Query/bin $ ruby main.rb
Enter the code or q for quit
>>db_open('vbhv')
users
persons
people
programmers
>>Users.first
/home/vbhv/git/R-Query/lib/r-query.rb:36:in `instance_eval': undefined method `execute' for nil:NilClass (NoMethodError)
Did you mean? exec
from /home/vbhv/git/R-Query/lib/r-query.rb:29:in `block (3 levels) in make_class'
from (eval):1:in `eval_this'
from /home/vbhv/git/R-Query/lib/r-query.rb:36:in `instance_eval'
from /home/vbhv/git/R-Query/lib/r-query.rb:36:in `eval_this'
from /home/vbhv/git/R-Query/lib/r-query.rb:43:in `code'
from /home/vbhv/git/R-Query/lib/r-query.rb:44:in `code'
from /home/vbhv/git/R-Query/lib/r-query.rb:44:in `code'
from main.rb:4:in `<main>'
Now the 'execute' function it is talking about is inside amalgalite. What am I doing wrong here?? Thanks in Advance!
The problem in this was that the new class formed dynamically doesn't know about the connection variable '#db'. Hence the code solves the problem.
#class_created.instance_variable_set(:#database, #db)
A big thanks to Jagdeep Singh.

Celluloid 0.17.3 giving unexpected "undefined method" error

I have started using Celluloid gem this morning for that first time. I am following this Railscasts tutorial and trying to figure things out.
I have a class called "SomeClass" and it has only one method. Here is the code:
require 'celluloid'
class SomeClass
include Celluloid
def initialize(name)
#name = name
end
def assholify()
puts "#{#name} has become an ASSHOLE."
end
end
When I create new instances of the class and call its method (with a bang i.e. "assholify!"), I am getting the undefined method 'assholify!', error. But Celluloid is supposed to trigger the method asynchronously when it is called with a bang. So here is how I am calling the method:
names = ['John', 'Tom', 'Harry']
names.each do |name|
n = SomeClass.new name
n.assholify!
end
Here is the full backtrace of the error:
I, [2016-09-09T11:28:02.488618 #3682] INFO -- : Celluloid 0.17.3 is running in BACKPORTED mode. [ http://git.io/vJf3J ]
/home/railsdev/.rvm/gems/ruby-2.3.1/gems/celluloid-0.17.3/lib/celluloid/calls.rb:42:in `rescue in check': undefined method `assholify!' for #<SomeClass:0x10897dc> (NoMethodError)
from /home/railsdev/.rvm/gems/ruby-2.3.1/gems/celluloid-0.17.3/lib/celluloid/calls.rb:39:in `check'
from /home/railsdev/.rvm/gems/ruby-2.3.1/gems/celluloid-0.17.3/lib/celluloid/calls.rb:26:in `dispatch'
from /home/railsdev/.rvm/gems/ruby-2.3.1/gems/celluloid-0.17.3/lib/celluloid/call/sync.rb:16:in `dispatch'
from /home/railsdev/.rvm/gems/ruby-2.3.1/gems/celluloid-0.17.3/lib/celluloid/cell.rb:50:in `block in dispatch'
from /home/railsdev/.rvm/gems/ruby-2.3.1/gems/celluloid-0.17.3/lib/celluloid/cell.rb:76:in `block in task'
from /home/railsdev/.rvm/gems/ruby-2.3.1/gems/celluloid-0.17.3/lib/celluloid/actor.rb:339:in `block in task'
from /home/railsdev/.rvm/gems/ruby-2.3.1/gems/celluloid-0.17.3/lib/celluloid/task.rb:44:in `block in initialize'
from /home/railsdev/.rvm/gems/ruby-2.3.1/gems/celluloid-0.17.3/lib/celluloid/task/fibered.rb:14:in `block in create'
from (celluloid):0:in `remote procedure call'
from /home/railsdev/.rvm/gems/ruby-2.3.1/gems/celluloid-0.17.3/lib/celluloid/call/sync.rb:45:in `value'
from /home/railsdev/.rvm/gems/ruby-2.3.1/gems/celluloid-0.17.3/lib/celluloid/proxy/sync.rb:22:in `method_missing'
from some_class.rb:18:in `block in <main>'
from some_class.rb:16:in `each'
from some_class.rb:16:in `<main>'
Why am I getting this error? Is it the right way to call the function? Also how do I get rid of Celluloid 0.17.3 is running in BACKPORTED mode. warning?
The undefined method error occurred because actor methods are not called with a bang in the recent versions of celluloid gem. Instead you call the method like this: n.async.assholify. So here is what the code should look like:
names = ['John', 'Tom', 'Harry']
names.each do |name|
n = SomeClass.new name
n.async.assholify # Instead of "n.assholify!"
end
For "Celluloid 0.17.0 is running in BACKPORTED mode" warning, take a look at this wiki. Backported Mode is the default, for a limited time. If you use require 'celluloid/current' instead of require 'celluloid', you should not see this warning.

rspec-puppet tests fail undefined method

I'm trying to write my first rspec test for a simple puppet class. Here's the class, rspec test and results. I'm new to rspec and would like to know what I'm doing wrong here. I follow the directions here http://rspec-puppet.com/setup/ to configure rspec-puppet for these tests. Thanks.
Class example for cron module init.pp
class cron {
service { 'crond' :
ensure => running,
enable => true
}
}
Rspec Test
require '/etc/puppetlabs/puppet/modules/cron/spec/spec_helper'
describe 'cron', :type => :module do
it { should contain_class('cron') }
it do should contain_service('crond').with(
'ensure' => 'running',
'enable' => 'true'
) end
end
Results
FF
Failures:
1) cron
Failure/Error: it { should contain_class('cron') }
NoMethodError:
undefined method `contain_class' for #<RSpec::Core::ExampleGroup::Nested_1:0x00000001c66d70>
# ./cron_spec.rb:5:in `block (2 levels) in <top (required)>'
2) cron
Failure/Error: it do should contain_service('crond').with(
NoMethodError:
undefined method `contain_service' for #<RSpec::Core::ExampleGroup::Nested_1:0x00000001c867b0>
# ./cron_spec.rb:6:in `block (2 levels) in <top (required)>'
Finished in 0.00237 seconds
2 examples, 2 failures
Failed examples:
rspec ./cron_spec.rb:5 # cron
rspec ./cron_spec.rb:6 # cron
Where did you pick up the
describe 'cron', :type => :module
syntax? That may be obsolete.
With current versions of rspec-puppet, you describe
classes
defined types
functions
hosts
You basically just want to put your spec right into spec/classes/cron_spec.rb, that should do half your work for you, e.g.
# spec/classes/cron.rb
require "#{File.join(File.dirname(__FILE__),'..','spec_helper.rb')}"
describe 'cron' do
it { should contain_service('crond').with('ensure' => 'running') }
it { should contain_service('crond').with('enable' => 'true') }
end
It is good practice to have distinct tests for each attribute value, so that possible future regressions can be identified more accurately.
Do see the README.
For a nice example of a well structured module test-suite see example42's modules.

Pure Ruby rspec test passes without method being defined

I have an rspec test on a pure Ruby model:
require 'spec_helper'
require 'organization'
describe Organization do
context '#is_root?' do
it "creates a root organization" do
org = Organization.new
expect { org.is_root?.to eq true }
end
end
end
My organization model looks like this:
class Organization
attr_accessor :parent
def initialize(parent = nil)
self.parent = parent
end
end
The output when running the tests:
bundle exec rspec spec/organization_spec.rb:6
Run options: include {:locations=>{"./spec/organization_spec.rb"=>[6]}}
.
Finished in 0.00051 seconds
1 example, 0 failures
When I run the test, it passes, despite the fact that the method is_root? doesn't exist on the model. I usually work in Rails, not pure Ruby, and I've never seen this happen. What is going on?
Thanks!
It should be:
expect(org.is_root?).to eq true
When you pass block to expect it is being wrapped in ExpectationTarget class (strictly speaking BlockExpectationTarget < ExpectationTarget). Since you didn't specify what you expect from this object, the block is never executed, hence no error is raised.
You are passing a block to expect, which is never being called. You can see this by setting an expectation on that block
expect { org.is_root?.to eq true }.to_not raise_error
1) Organization#is_root? creates a root organization
Failure/Error: expect { puts "HI";org.is_root?.to eq true }.to_not raise_error
expected no Exception, got #<NoMethodError: undefined method `is_root?' for #<Organization:0x007ffa798c2ed8 #parent=nil>> with backtrace:
# ./test_spec.rb:15:in `block (4 levels) in <top (required)>'
# ./test_spec.rb:15:in `block (3 levels) in <top (required)>'
# ./test_spec.rb:15:in `block (3 levels) in <top (required)>'
Or by just putting a plain raise or puts inside the block, neither of which will be called:
expect { puts "HI"; raise; org.is_root?.to eq true }
The block form is used for expecting that a piece of code raises an exception or not. The correct syntax for checking values is:
expect(org.is_root?).to eq(true)

TypeError: superclass mismatch for class Word in Ruby

I am creating a Word class and I am getting an error:
TypeError: superclass mismatch for class Word
Here is the irb code:
irb(main):016:0> class Word
irb(main):017:1> def palindrome?(string)
irb(main):018:2> string == string.reverse
irb(main):019:2> end
irb(main):020:1> end
=> nil
irb(main):021:0> w = Word.new
=> #<Word:0x4a8d970>
irb(main):022:0> w.palindrome?("foobar")
=> false
irb(main):023:0> w.palindrome?("level")
=> true
irb(main):024:0> class Word < String
irb(main):025:1> def palindrome?
irb(main):026:2> self == self.reverse
irb(main):027:2> end
irb(main):028:1> end
TypeError: superclass mismatch for class Word
from (irb):24
from C:/Ruby193/lib/ruby/gems/1.9.1/gems/railties-3.2.1/lib/rails/commands/console.rb:47:in `start'
from C:/Ruby193/lib/ruby/gems/1.9.1/gems/railties-3.2.1/lib/rails/commands/console.rb:8:in `start'
from C:/Ruby193/lib/ruby/gems/1.9.1/gems/railties-3.2.1/lib/rails/commands.rb:41:in `<top (required)>'
from script/rails:6:in `require'
from script/rails:6:in `<main>'
A thumb rule for irb (either way irb or rails console)
If you are creating the same class twice with inheritance (superclass), exit the irb instance and create it again. Why this? Because otherwise class conflicts will happen.
In your case, you are using Windows (found from the question), so just type exit on DOS prompt and again type irb or rails console and create your Word class and it should work. Please let me know if it doesn't work for you.
The reason it gives you a superclass mismatch error is because you have already defined the Word class as inheriting from Object
class Word
...
end
In Ruby (like in most dynamic languages) you can monkey-patch classes by reopening the definition and modifying the class. However, in your instance, when you are reopening the class you are also attempting to redefine the class as inheriting from the super class String.
class Word < String
...
end
Once a class and it's inheritance structure have been defined, you cannot define it again.
As a few people have said, exiting and restarting irb will allow you to start from scratch in defining the Word class.
link664 has clearly explained the problem.
However, there's an easier fix without quitting irb (and losing all your other work).
You can delete an existing class definition this way.
irb(main):051:0> Object.send(:remove_const, :Word)
and you can verify with:
irb(main):052:0> Word.public_instance_methods
which should return:
NameError: uninitialized constant Word
from (irb):52
An easy way to bypass this issue is to encapsulate both classes between different modules:
> module M
> class Word
> def palindrome?(string)
> string == string.reverse
> end
> end
> end
=> nil
> w = M::Word.new
=> #<Word:0x4a8d970>
> w.palindrome?("foobar")
=> false
> w.palindrome?("level")
=> true
> module N
> class Word < String
> def palindrome?
> self == self.reverse
> end
> end
> end
> N::Word.new("kayak").palindrome?
=> true

Resources