How to write spec for concern - ruby

I created a concern below. what i am doing is i am mapping the column from a table that has values 0, 1, 2 and returning strings for those in JSON. Can someone guide me how can i write unit test cases for it?
module User
extend ActiveSupport::Concern
included do
def user_mapping(user_in_number)
user_hash = {
'0'=> 'Support',
'1'=> 'Developer',
'2'=> 'Business Analyst'
}.freeze
user_hash[user_in_number]
end
end
end
Thanks

For any module you can do this:
subject = Class.new do
include User
end.new
assert subject.user_mapping('0'), 'Support'
Class.new creates an anonymous class, the block is evaluated in the context of the anonymous class, so acting like the body of a regular class.
Then create an instance of the anonymous class and call the methods as defined by the included module.
By the way the actual method does not need to assign so many vars:
UserMap = {
'0'=> 'Support',
'1'=> 'Developer',
'2'=> 'Business Analyst'
}.freeze
def user_mapping(user_in_number)
UserMap.fetch(user_in_number)
end
fetch will raise if the given key is not found.
I'd might also reconsider the name User for a module, will you never need a User class...

Related

What is a Ruby factory method?

I understand that a factory method is a class method that utilises the self keyword and instantiates an object of it's own class. I don't understand how this is useful or how it can extend the functionality of initialize method.
I'm working on a project creating a command line address book that asks me to use a factory pattern on the Person class so that I can create a Trainee or Instructor (subclasses) with different attributes.
A factory class is a clean way to have a single factory method that produces various kind of objects.
It takes a parameter, a parameter that tells the method which kind of object to create. For example to generate an Employee or a Boss, depending on the symbol that is passed in:
class Person
def initialize(attributes)
end
end
class Boss
def initialize(attributes)
end
end
class Employee
def initialize(attributes)
end
end
class PersonFactory
TYPES = {
employee: Employee,
boss: Boss
}
def self.for(type, attributes)
(TYPES[type] || Person).new(attributes)
end
end
and then:
employee = PersonFactory.for(:employee, name: 'Danny')
boss = PersonFactory.for(:boss, name: 'Danny')
person = PersonFactory.for(:foo, name: 'Danny')
I also wrote a more detailed blog post about that topic: The Factory Pattern
The Factory Method Pattern at least allows you to give an expressive name to what could otherwise be a complicated or opaque constructor. For instance if you have a constructor that takes a bunch of parameters, it may not be clear why to the caller, having a named Factory method or methods could potentially hide the complexity of the object creation and make your code more expressive of what is actually going on.
So in your case a bad design may be:
trainee = Person.new true
or
instructor = Person.new false
Where true or false branches to creating an instructor or trainee.
This could be improved by using a Factory method to clarify what is going on:
trainee = Person.create_trainee
instructor = Person.create_instructor
Why bother with factory methods?
(A) To simplify things:
Creating objects can be complicated, and
you may need to do this multiple times.
It's hard to remember:
# ugh - too much work!
driver = Person.new
engine = Brrrm.new
engine.turbo_charged = true
engine.max_rpm = 100000
car = Porsche.new
car.driver = driver
car.engine = engine
# preference - less to remember
ben = PersonFactory.create("ben")
car = PorscheFactory.create(ben)
# and you get the following for free, without remembering:
car.turbo_charged # => true
car.engine # => brrrm
car.driver # => ben_koshy
car.driver.personality # => :excellent_dude
# you can mix and match default values with options.
# generally speaking you want to inject as much as you can
# i.e. inverting dependencies. I make these illustrates to
# explain a concept, not as an example of great coding.
(B) To allow for overridding / stubbing
If you are writing testable code, you might want to create your own specialised 'crash dummy vehicle' so you can test collisions etc. If you have a factory method / object, then you can do this easily. This is a somewhat adavanced topic - google "creating a seam" or "dependency injection" for more info.

Referencing parent objects from children

Say you have a User class:
class User
attr_accessor :widgets
end
and a Widget:
class Widget
attr_accessor :owner
end
and you assign some widgets to a user:
user = User.new
widget = Widget.new
widget.owner = user
widget2 = Widget.new
widget2.owner = user
user.widgets = [widget, widget2]
Now you have a recursion of user → widgets → owner. user.inspect shows the same user reference once for every widget, cluttering the output:
user.widgets.first.owner.widgets.first.owner
=> #<User:0x00000001cac820 #widgets=[#<Widget:0x00000001ca45f8 #owner=#<User:0x00000001cac820 ...>>, #<Widget:0x00000001c87a20 #owner=#<User:0x00000001cac820 ...>>]>
If we were to reduce this data structure to a hash we'd have:
{ user:
{ widgets: [ { widget: ... },
{ widget: ... } ]
}
}
We could pass this around instead of assigning widget.owner and it would be easy enough to reference the parent user.
I wonder if there's a way to access the parent object through the child without having to assign owner to all child objects, an interface that could work like this:
user = User.new
widget = Widget.new
user.widgets = [widget]
widget.parent
# => #<User:... #widgets=[#<Widget:...>]>
What you're looking for is a custom writer. There is no parent method or equivalent on the Object or BaseObject class, because implementing that would require objects to track every other object that happened to point to it. When you want that functionality though, custom writers make it simple and easy to implement.
class Widget
attr_accessor :owner
end
class User
attr_reader :widgets
def widgets=(widgets)
#widgets = widgets
widgets.each do |widget|
widget.owner = self
end
end
end
user = User.new
widget = Widget.new
user.widgets = [widget]
widget.owner #=> #<User:... #widgets=[#<Widget:...>]>
Note that this custom writer only covers regular assignment, like user.widgets = [widget]. If you wanted to do something like user.widgets << widget, the new widget wouldn't be assigned an owner. If you want to be able to do that, you'll either have to monkeypatch Array like this (not recommended), or you'll have to create a WidgetCollection class that likely inherits from Array. That's what ActiveRecord::Associations does. Speaking of which, if you happen to be using Rails, definitely look into using ActiveRecord to do all this for you. It looks like you're asking about plain old ruby so I'm giving you a vanilla ruby answer.
Thought of sharing the explanation I've come up with. It has no solid proof, but might help.
Firstly, there isn't any problem with loop chaining objects like that. The code wouldn't work fine just like that if there was a problem with loop chains, it would either crash or show an error. So it might be handling these kind of loop references in a way, but it really makes sense if you understand that variables are just references to objects.
I mean when you simply access a User instance user, it doesn't just load up everything inside it recursively. It just does nothing or maybe just takes out the reference. What really sets up the recursion is the inspect method, which recursively inspects all the instance variables inside the instance. But it does handle the deep inspects, with the .....
So your real problem should only be with making inspects look compact. You can override that method, so that it won't recurse, and gives you a nice message. Example :
class User
attr_accessor :widgets
def initialize
#widgets =[]
end
def inspect
"[User:objid=#{object_id};widgets=#{widgets.size}]"
end
end
class Widget
attr_accessor :owner
def inspect
"#[Widget:objid=#{object_id}]"
end
end
The interface can remain the same.
user = User.new
widget = Widget.new
widget.owner = user
widget2 = Widget.new
widget2.owner = user
user.widgets = [widget, widget2]
user.widgets.first.owner.widgets.first.owner
# => #[User:objid=-590412418;widgets=2]

ruby: calling a instance method without using instance

I know in ruby, when we call an instance method, we need to firstly instantiate a class object.
But when I see a open sourced code I got confused.
The code is like this:
File Message.rb
require 'json'
module Yora
module Message
def serialize(msg)
JSON.generate(msg)
end
def deserialize(raw, symbolized_key = true)
msg = JSON.parse(raw, create_additions: true)
if symbolized_key
Hash[msg.map { |k, v| [k.to_sym, v] }]
else
msg
end
end
end
end
File. Persistance.rb
require 'fileutils'
require_relative 'message'
module Yora
module Persistence
class SimpleFile
include Message
def initialize(node_id, node_address)
#node_id, #node_address = node_id, node_address
FileUtils.mkdir_p "data/#{node_id}"
#log_path = "data/#{node_id}/log.txt"
#metadata_path = "data/#{node_id}/metadata.txt"
#snapshot_path = "data/#{node_id}/snapshot.txt"
end
def read_metadata
metadata = {
current_term: 0,
voted_for: nil,
cluster: { #node_id => #node_address }
}
if File.exist?(#metadata_path)
metadata = deserialize(File.read(#metadata_path)) #<============
end
$stderr.puts "-- metadata = #{metadata}"
metadata
end
.....
You can see the line I marked with "<==="
It uses deserialize function that been defined in message class.
And from message class we can see that method is a instance method, not class method.
So why can we call it without instantiating anything like this?
thanks
Message ist an module. Your Class SimpleFile includes this module. so the module methods included in your class SimpleFile. that means, all module methods can now be used like as methods from SimpleFile
see http://ruby-doc.org/core-2.2.0/Module.html for more infos about module in ruby. it's a great feature.
It is being called on an instance. In Ruby, if you leave out the explicit receiver of the message send, an implicit receiver of self is assumed. So, deserialize is being called on an instance, namely self.
Note that this exact same phenomenon also occurs in other places in your code, much earlier (in line 1, in fact):
require 'fileutils'
require_relative 'message'
Here, you also have two method calls without an explicit receiver, which means that the implicit receiver is self.

Static local variables for methods in Ruby?

I have this:
def valid_attributes
{ :email => "some_#{rand(9999)}#thing.com" }
end
For Rspec testing right? But I would like to do something like this:
def valid_attributes
static user_id = 0
user_id += 1
{ :email => "some_#{user_id}#thing.com" }
end
I don't want user_id to be accessible from anywhere but that method,
is this possible with Ruby?
This is a closure case. Try this
lambda {
user_id = 0
self.class.send(:define_method, :valid_attributes) do
user_id += 1
{ :email => "some_#{user_id}#thing.com" }
end
}.call
Wrapping everything in lambda allows the variables defined within lambda to only exist in the scope. You can add other methods also. Good luck!
This answer is a little larger in scope than your question, but I think it gets at the root of what you're trying to do, and will be the easiest and most maintainable.
I think what you're really looking for here is factories. Try using something like factory_girl, which will make a lot of testing much easier.
First, you'd set up a factory to create whatever type of object it is you're testing, and use a sequence for the email attribute:
FactoryGirl.define do
factory :model do
sequence(:email) {|n| "person#{n}#example.com" }
# include whatever else is required to make your model valid
end
end
Then, when you need valid attributes, you can use
Factory.attributes_for(:model)
You can also use Factory.create and Factory.build to create saved and unsaved instances of the model.
There's explanation of a lot more of the features in the getting started document, as well as instructions on how to add factories to your project.
You can use a closure:
def validator_factory
user_id = 0
lambda do
user_id += 1
{ :email => "some_#{user_id}#thing.com" }
end
end
valid_attributes = validator_factory
valid_attributes.call #=> {:email=>"some_1#thing.com"}
valid_attributes.call #=> {:email=>"some_2#thing.com"}
This way user_id won't be accessible outside.
I'd use an instance variable:
def valid_attributes
#user_id ||= 0
#user_id += 1
{ :email => "some_#{#user_id}#thing.com" }
end
The only variables Ruby has are local variables, instance variables, class variables and global variables. None of them fit what you're after.
What you probably need is a singleton that stores the user_id, and gives you a new ID number each time. Otherwise, your code won't be thread-safe.

"Here methods" in Ruby?

I'm writing a few helpers to DRY up my tests. I pictured something like:
class ActiveSupport::TestCase
def self.test_presence_validation_of model, attribute
test "should not save #{model.to_s} with null #{attribute.to_s}", <<-"EOM"
#{model.to_s} = Factory.build #{model.to_sym}, #{attribute.to_sym} => nil
assert !#{model.to_s}.save, '#{model.to_s.capitalize} with null #{attribute.to_s} saved to the Database'
EOM
# Another one for blank attribute.
end
end
So that this:
class MemberTest < ActiveSupport::TestCase
test_presence_validation_of :member, :name
end
Executes exactly this at MemberTest class scope:
test 'should not save member with null name' do
member = Factory.build :member, :name => nil
assert !member.save, 'Member with null name saved to the Database'
end
Is it possible to do it this way (with a few adaptations, of course; I doubt my "picture" works), or do I have to use class_eval?
Have you seen Shoulda? It's great for testing common Rails functionality such as validations, relationships etc. https://github.com/thoughtbot/shoulda-matchers
In this case, it seems class_eval is necessary since I want to interpolate variable names into actual code.
Illustrated here.

Resources