Tutor
For Ruby 2+
Supplemental teachings for your Ruby classes.
Table of Contents
- Introduction
- Installation
- Features
- Attributes
- Type-checking
- Defaults
- Aliasing
- Custom getter & setter
- Inheritance
- Attributes
- Testing
- Development
- Contributing
- License
Tutor adds some useful patterns and idioms to mixin to your classes.
e.g. Attributes with type and defaults
class Vertex; end
class Polygon
include Tutor::Attributes
attribute(:sides, type: Integer, default: 3)
attribute(:vertices, default: lambda { |polygon| Array.new(polygon.sides) { Vertex.new } })
end
p = Polygon.new
p.intialize_attributes
p.sides # => 3
p.vertices # => [#<Vertex>, #<Vertex>, #<Vertex>]If you're not using Bundler...
Install the gem via:
gem install tutor
Then require it into your application with:
require 'tutor'
If you're using Bundler...
Add the gem to your Gemfile:
gem 'tutor'
And then bundle install to install the gem and its dependencies.
Enable attributes on a class by including Tutor::Attributes module into the class/module you want to add attributes to.
class Polygon
include Tutor::Attributes
endThen add an attribute to add a name and name= method to the class.
class Polygon
include Tutor::Attributes
attribute(:sides)
end
Polygon.method_defined?(:sides) # => true
Polygon.method_defined?(:sides=) # => trueOf course, if this is all you need, then you might be better served just using attr_accessor. However, attribute gives you access to a few additional options.
attribute(:sides, type: Integer)Add type-checking by adding the type option, and the class you want to type check against. Any value that is of that type, or inherits from it, will be permitted. Any other value will raise an ArgumentError.
By default, nil passes the type check. However, if you want to disallow nil values, you can set the nullable: false option.
attribute(:sides, type: Integer, nullable: false)attribute(:vertices, default: 3)Adding the default option sets a default value for attribute, when initialize_attributes is called. To automatically set these defaults, add the function call to your initialize function.
def initialize
initialize_attributes
endYou can also pass it a Hash of attributes, which will override any default values.
def initialize(custom_attributes = {})
initialize_attributes(custom_attributes)
endYou can also set the default to a Proc or lambda. This is useful for non-static values, like class objects, where you want unique default objects per instance of your class.
# NOTE: The following two definitions are NOT equivalent.
# Sets default to the same object for all instances.
attribute(:vertices, default: Vertex.new)
# Sets default to the different object for each instance.
attribute(:vertices, default: -> { Vertex.new })These blocks optionally can be defined to accept an argument. In which case, the object being initialized will be passed in. Any explicitly provided attribute values, or previously set defaults will be accessible.
attribute :vertices,
default: lambda { |object| object.sides.times { Vertex.new } }attribute(:nodes)
attribute(:vertices, alias: :nodes)Alias any other attribute with the alias option, and the name of the method.
attribute :vertices,
get: lambda { |object| object.nodes },
set: lambda { |object, value| object.nodes = value }You can add custom get or set behavior for the attribute, by passing a Proc into the get or set options.
attribute :vertices,
get: lambda { |object| object.nodes },
set: falsePassing a false or nil value for either get or set will skip that method declaration.
class Angle; end
class Polygon
include Tutor::Attributes
attribute(:sides, type: Integer)
end
class Triangle < Polygon
include Tutor::Attributes
attribute(:angles, default: lambda { |o| o.sides.times { Angle.new } })
end
Triangle.new.initialize_attributes(sides: 3)
# => #<Triangle @sides=3, @angles=[ #<Angle>, #<Angle>, #<Angle>]>Attributes can be initialized and accessed from inheriting classes. If an attribute name in a subclass conflicts with an already existing attribute or method, it will raise a NameError. You can, however, override the parent by passing the override option.
class Angle; end
class Polygon
include Tutor::Attributes
attribute(:sides, type: Integer, default: 3)
end
class Square < Polygon
include Tutor::Attributes
attribute(:sides, type: Integer, default: 4, override: true)
end
Square.new.initialize_attributes
# => #<Square @sides=4>Description pending.
Install dependencies using bundle install. Run tests using bundle exec rspec.
Bug reports and pull requests are welcome on GitHub at https://github.com/delner/tutor.
The gem is available as open source under the terms of the MIT License.