README.md in sinclair-1.5.0 vs README.md in sinclair-1.5.1
- old
+ new
@@ -12,11 +12,11 @@
that enables creation of methods on the fly through class
methods
Yard Documentation
-------------------
-https://www.rubydoc.info/gems/sinclair/1.5.0
+https://www.rubydoc.info/gems/sinclair/1.5.1
Installation
---------------
- Install it
@@ -35,11 +35,11 @@
```
Usage
---------------
# Sinclair
-Sinclair can actully be used in several ways, as an stand alone object capable of
+Sinclair can actually be used in several ways, as a stand alone object capable of
adding methods to your class on the fly, as a builder inside a class method
or by extending it for more complex logics
## Stand Alone usage creating methods on the fly:
@@ -50,16 +50,21 @@
builder = Sinclair.new(Clazz)
builder.add_method(:twenty, '10 + 10')
builder.add_method(:eighty) { 4 * twenty }
+ builder.add_class_method(:one_hundred) { 100 }
+ builder.add_class_method(:one_hundred_twenty, 'one_hundred + 20')
builder.build
instance = Clazz.new
puts "Twenty => #{instance.twenty}" # Twenty => 20
puts "Eighty => #{instance.eighty}" # Eighty => 80
+
+ puts "One Hundred => #{Clazz.one_hundred}" # One Hundred => 100
+ puts "One Hundred => #{Clazz.one_hundred_twenty}" # One Hundred Twenty => 120
```
## Builder in class method:
```ruby
@@ -118,10 +123,47 @@
person.age # returns 21
person.username # returns 'lordbob'
person.email # returns 'lord@bob.com'
```
+```ruby
+ module EnvSettings
+ def env_prefix(new_prefix=nil)
+ @env_prefix = new_prefix if new_prefix
+ @env_prefix
+ end
+
+ def from_env(*method_names)
+ builder = Sinclair.new(self)
+
+ method_names.each do |method_name|
+ env_key = [env_prefix, method_name].compact.join('_').upcase
+
+ builder.add_class_method(method_name, cached: true) do
+ ENV[env_key]
+ end
+
+ builder.build
+ end
+ end
+ end
+
+ class MyServerConfig
+ extend EnvSettings
+
+ env_prefix :server
+
+ from_env :host, :port
+ end
+
+ ENV['SERVER_HOST'] = 'myserver.com'
+ ENV['SERVER_PORT'] = '9090'
+
+ MyServerConfig.host # returns 'myserver.com'
+ MyServerConfig.port # returns '9090'
+```
+
## Extending the builder
```ruby
class ValidationBuilder < Sinclair
@@ -364,78 +406,123 @@
end
Client.config.url # returns 'http://interstella.com:8080'
```
+# Sinclair::Settable
+
+Settable allows classes to extract configuration from environments through
+a simple meta-programable way
+
+```ruby
+ class ServiceClient
+ extend Sinclair::EnvSettable
+ attr_reader :username, :password, :host, :port
+
+ settings_prefix 'SERVICE'
+
+ with_settings :username, :password, port: 80, hostname: 'my-host.com'
+
+ def self.default
+ @default ||= new
+ end
+
+ def initialize(
+ username: self.class.username,
+ password: self.class.password,
+ port: self.class.port,
+ hostname: self.class.hostname
+ )
+ @username = username
+ @password = password
+ @port = port
+ @hostname = hostname
+ end
+ end
+
+ ENV['SERVICE_USERNAME'] = 'my-login'
+ ENV['SERVICE_HOSTNAME'] = 'host.com'
+
+ ServiceClient.default # returns #<ServiceClient:0x0000556fa1b366e8 @username="my-login", @password=nil, @port=80, @hostname="host.com">'
+```
+
RSspec matcher
---------------
You can use the provided matcher to check that your builder is adding a method correctly
```ruby
-
class DefaultValue
delegate :build, to: :builder
- attr_reader :klass, :method, :value
+ attr_reader :klass, :method, :value, :class_method
- def initialize(klass, method, value)
+ def initialize(klass, method, value, class_method: false)
@klass = klass
@method = method
@value = value
+ @class_method = class_method
end
private
def builder
@builder ||= Sinclair.new(klass).tap do |b|
- b.add_method(method) { value }
+ if class_method
+ b.add_class_method(method) { value }
+ else
+ b.add_method(method) { value }
+ end
end
end
end
- require 'sinclair/matchers'
- RSpec.configure do |config|
- config.include Sinclair::Matchers
- end
+ RSpec.describe Sinclair::Matchers do
+ subject(:builder_class) { DefaultValue }
- RSpec.describe DefaultValue do
- let(:klass) { Class.new }
- let(:method) { :the_method }
- let(:value) { Random.rand(100) }
- let(:builder) { described_class.new(klass, method, value) }
- let(:instance) { klass.new }
+ let(:klass) { Class.new }
+ let(:method) { :the_method }
+ let(:value) { Random.rand(100) }
+ let(:builder) { builder_class.new(klass, method, value) }
+ let(:instance) { klass.new }
context 'when the builder runs' do
it do
- expect do
- described_class.new(klass, method, value).build
- end.to add_method(method).to(instance)
+ expect { builder.build }.to add_method(method).to(instance)
end
end
context 'when the builder runs' do
it do
- expect do
- described_class.new(klass, method, value).build
- end.to add_method(method).to(klass)
+ expect { builder.build }.to add_method(method).to(klass)
end
end
+
+ context 'when adding class methods' do
+ subject(:builder) { builder_class.new(klass, method, value, class_method: true) }
+
+ context 'when the builder runs' do
+ it do
+ expect { builder.build }.to add_class_method(method).to(klass)
+ end
+ end
+ end
end
```
```bash
> bundle exec rspec
```
```string
-
-DefaultValue
+Sinclair::Matchers
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
-
+ should add method 'the_method' to #<Class:0x000055e5d9b7f150> instances
+ when the builder runs
+ should add method 'the_method' to #<Class:0x000055e5d9b8c0a8> instances
+ when adding class methods
+ when the builder runs
+ should add method class_method 'the_method' to #<Class:0x000055e5d9b95d88>
```
Projects Using
---------------