README.md in sinclair-1.1.3 vs README.md in sinclair-1.2.0
- old
+ new
@@ -1,168 +1,191 @@
Sinclair
========
[![Code Climate](https://codeclimate.com/github/darthjee/sinclair/badges/gpa.svg)](https://codeclimate.com/github/darthjee/sinclair)
[![Test Coverage](https://codeclimate.com/github/darthjee/sinclair/badges/coverage.svg)](https://codeclimate.com/github/darthjee/sinclair/coverage)
[![Issue Count](https://codeclimate.com/github/darthjee/sinclair/badges/issue_count.svg)](https://codeclimate.com/github/darthjee/sinclair)
+[![Gem Version](https://badge.fury.io/rb/sinclair.svg)](https://badge.fury.io/rb/sinclair)
![sinclair](https://raw.githubusercontent.com/darthjee/sinclair/master/sinclair.jpg)
This gem helps the creation of complex concern with class methods
+Yard Documentation
+-------------------
+https://www.rubydoc.info/gems/sinclair/1.2.0
+
Installation
---------------
- Install it
- ```ruby
- gem install sinclair
- ```
+```ruby
+ gem install sinclair
+```
- Or add Sinclairn to your `Gemfile` and `bundle install`:
- ```ruby
- gem 'sinclair'
- ```
+```ruby
+ gem 'sinclair'
+```
- ```bash
- bundle install sinclair
- ```
+```bash
+ bundle install sinclair
+```
-Yard Documentation
--------------------
-https://www.rubydoc.info/gems/sinclair/1.1.3
-
Usage
---------------
The concern builder can actully be used in two ways, as an stand alone object capable of
adding methods to your class or by extending it for more complex logics
- Stand Alone usage:
- ```ruby
+```ruby
- class Clazz
- end
+ class Clazz
+ end
- builder = Sinclair.new(Clazz)
+ builder = Sinclair.new(Clazz)
- builder.add_method(:twenty, '10 + 10')
- builder.add_method(:eighty) { 4 * twenty }
- builder.build
+ builder.add_method(:twenty, '10 + 10')
+ builder.add_method(:eighty) { 4 * twenty }
+ builder.build
- instance = Clazz.new
+ instance = Clazz.new
- puts "Twenty => #{instance.twenty}"
- puts "Eighty => #{instance.eighty}"
- ```
+ puts "Twenty => #{instance.twenty}" # Twenty => 20
+ puts "Eighty => #{instance.eighty}" # Eighty => 80
+```
- ```string
-
- Twenty => 20
- Eighty => 80
- ```
-
- Extending the builder
- ```ruby
+```ruby
- class ValidationBuilder < Sinclair
- delegate :expected, to: :options_object
+ class ValidationBuilder < Sinclair
+ delegate :expected, to: :options_object
- def initialize(klass, options={})
- super
- end
+ def initialize(klass, options={})
+ super
+ end
- def add_validation(field)
- add_method("#{field}_valid?", "#{field}.is_a?#{expected}")
- end
+ def add_validation(field)
+ add_method("#{field}_valid?", "#{field}.is_a?#{expected}")
+ end
- def add_accessors(fields)
- klass.send(:attr_accessor, *fields)
- end
+ def add_accessors(fields)
+ klass.send(:attr_accessor, *fields)
end
+ end
- module MyConcern
- extend ActiveSupport::Concern
+ module MyConcern
+ extend ActiveSupport::Concern
- class_methods do
- def validate(*fields, expected_class)
- builder = ::ValidationBuilder.new(self, expected: expected_class)
+ class_methods do
+ def validate(*fields, expected_class)
+ builder = ::ValidationBuilder.new(self, expected: expected_class)
- validatable_fields.concat(fields)
- builder.add_accessors(fields)
+ validatable_fields.concat(fields)
+ builder.add_accessors(fields)
- fields.each do |field|
- builder.add_validation(field)
- end
-
- builder.build
+ fields.each do |field|
+ builder.add_validation(field)
end
- def validatable_fields
- @validatable_fields ||= []
- end
+ builder.build
end
- def valid?
- self.class.validatable_fields.all? do |field|
- public_send("#{field}_valid?")
- end
+ def validatable_fields
+ @validatable_fields ||= []
end
end
- class MyClass
- include MyConcern
- validate :name, :surname, String
- validate :age, :legs, Integer
-
- def initialize(name: nil, surname: nil, age: nil, legs: nil)
- @name = name
- @surname = surname
- @age = age
- @legs = legs
+ def valid?
+ self.class.validatable_fields.all? do |field|
+ public_send("#{field}_valid?")
end
end
+ end
- instance = MyClass.new
- ```
+ class MyClass
+ include MyConcern
+ validate :name, :surname, String
+ validate :age, :legs, Integer
+ def initialize(name: nil, surname: nil, age: nil, legs: nil)
+ @name = name
+ @surname = surname
+ @age = age
+ @legs = legs
+ end
+ end
+
+ instance = MyClass.new
+```
+
the instance will respond to the methods
```name``` ```name=``` ```name_valid?```
```surname``` ```surname=``` ```surname_valid?```
```age``` ```age=``` ```age_valid?```
```legs``` ```legs=``` ```legs_valid?```
```valid?```.
- ```ruby
+```ruby
+ valid_object = MyClass.new(
+ name: :name,
+ surname: 'surname',
+ age: 20,
+ legs: 2
+ )
+ valid_object.valid? # returns true
+```
- valid_object = MyClass.new(
- name: :name,
- surname: 'surname',
- age: 20,
- legs: 2
- )
- valid_object.valid? # returns true
- ```
+```ruby
- ```ruby
+ invalid_object = MyClass.new(
+ name: 'name',
+ surname: 'surname',
+ age: 20,
+ legs: 2
+ )
+ invalid_object.valid? # returns false
+```
- invalid_object = MyClass.new(
- name: 'name',
- surname: 'surname',
- age: 20,
- legs: 2
- )
- invalid_object.valid? # returns false
- ```
+ - Caching the result
+ If wanted, the result of the method can be stored in an
+ instance variable with the same name
+```ruby
+ class MyModel
+ attr_accessor :base, :expoent
+ end
+
+ builder = Sinclair.new(MyModel)
+
+ builder.add_method(:cached_power, cached: true) do
+ base ** expoent
+ end
+
+ # equivalent of builder.add_method(:cached_power) do
+ # @cached_power ||= base ** expoent
+ # end
+
+ builder.build
+
+ model.base = 3
+ model.expoent = 2
+
+ model.cached_power # returns 9
+ model.expoent = 3
+ model.cached_power # returns 9 (from cache)
+```
+
RSspec matcher
---------------
You can use the provided matcher to check that your builder is adding a method correctly
- ```ruby
+```ruby
class DefaultValue
delegate :build, to: :builder
attr_reader :klass, :method, :value
@@ -207,21 +230,21 @@
described_class.new(klass, method, value).build
end.to add_method(method).to(klass)
end
end
end
- ```
+```
- ```bash
+```bash
- > bundle exec rspec
- ```
+> bundle exec rspec
+```
- ```string
+```string
- DefaultValue
- when the builder runs
- should add method 'the_method' to #<Class:0x0000000146c160> instances
- when the builder runs
- should add method 'the_method' to #<Class:0x0000000143a1b0> instances
+DefaultValue
+ when the builder runs
+ should add method 'the_method' to #<Class:0x0000000146c160> instances
+ when the builder runs
+ should add method 'the_method' to #<Class:0x0000000143a1b0> instances
- ```
+```