Skip to content

Commit

Permalink
Extract configuration objects!
Browse files Browse the repository at this point in the history
- Remove serializers and readers logic from Rambling::Trie module
- Add Configuration module
- Add Configuration::Properties module
- Unify readers and serializers configuration in Configuration::ProviderCollection
- Ensure tests use new configuration options appropriately

[Related to #10]
  • Loading branch information
gonzedge committed Jan 9, 2017
1 parent 4ad7d25 commit 02e7db2
Show file tree
Hide file tree
Showing 7 changed files with 357 additions and 38 deletions.
48 changes: 23 additions & 25 deletions lib/rambling/trie.rb
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
require 'forwardable'

%w{
forwardable comparable compressable compressor container enumerable
inspectable invalid_operation readers serializers stringifyable node
missing_node compressed_node raw_node version
forwardable comparable compressable compressor configuration container
enumerable inspectable invalid_operation readers serializers stringifyable
node missing_node compressed_node raw_node version
}.each do |file|
require File.join('rambling', 'trie', file)
end
Expand All @@ -12,6 +13,13 @@ module Rambling
# Entry point for rambling-trie API.
module Trie
class << self
extend Rambling::Trie::Forwardable

delegate [
:readers,
:serializers
] => :properties

# Creates a new Rambling::Trie. Entry point for the Rambling::Trie API.
# @param [String, nil] filepath the file to load the words from.
# @param [Reader, nil] reader the file parser to get each word. See
Expand All @@ -21,7 +29,7 @@ class << self
def create filepath = nil, reader = nil
Rambling::Trie::Container.new do |container|
if filepath
reader ||= default_reader
reader ||= readers.resolve filepath
reader.each_word filepath do |word|
container << word
end
Expand All @@ -38,7 +46,7 @@ def create filepath = nil, reader = nil
# @return [Container] the trie just loaded.
# @yield [Container] the trie just loaded.
def load filepath, serializer = nil
serializer ||= serializer filepath
serializer ||= serializers.resolve filepath
root = serializer.load filepath
Rambling::Trie::Container.new root do |container|
yield container if block_given?
Expand All @@ -52,32 +60,22 @@ def load filepath, serializer = nil
# serializing and dumping the trie into disk. See
# {Rambling::Trie::Serializers Serializers}.
def dump trie, filepath, serializer = nil
serializer ||= serializer filepath
serializer ||= serializers.resolve filepath
serializer.dump trie.root, filepath
end

private

def default_reader
Rambling::Trie::Readers::PlainText.new
# Provides configuration properties for the Rambling::Trie gem.
# @return [Properties] the configured properties of the gem.
# @yield [Properties] the configured properties of the gem.
def config
yield properties if block_given?
properties
end

def default_serializer
serializers[:marshal]
end

def serializer filepath
format = File.extname filepath
format.slice! 0
serializers[format.to_sym] || default_serializer
end
private

def serializers
{
marshal: Rambling::Trie::Serializers::Marshal.new,
yml: Rambling::Trie::Serializers::Yaml.new,
yaml: Rambling::Trie::Serializers::Yaml.new,
}
def properties
@properties ||= Rambling::Trie::Configuration::Properties.new
end
end
end
Expand Down
11 changes: 11 additions & 0 deletions lib/rambling/trie/configuration.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
%w{properties provider_collection}.each do |file|
require File.join('rambling', 'trie', 'configuration', file)
end

module Rambling
module Trie
# Namespace for configuration classes.
module Configuration
end
end
end
38 changes: 38 additions & 0 deletions lib/rambling/trie/configuration/properties.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
module Rambling
module Trie
module Configuration
class Properties
attr_reader :readers, :serializers

def initialize
reset
end

def reset
reset_readers
reset_serializers
end

private

attr_writer :readers, :serializers

def reset_readers
plain_text_reader = Rambling::Trie::Readers::PlainText.new

self.readers = Rambling::Trie::Configuration::ProviderCollection.new 'reader', txt: plain_text_reader
end

def reset_serializers
marshal_serializer = Rambling::Trie::Serializers::Marshal.new
yaml_serializer = Rambling::Trie::Serializers::Yaml.new

self.serializers = Rambling::Trie::Configuration::ProviderCollection.new 'serializer',
marshal: marshal_serializer,
yml: yaml_serializer,
yaml: yaml_serializer
end
end
end
end
end
62 changes: 62 additions & 0 deletions lib/rambling/trie/configuration/provider_collection.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
module Rambling
module Trie
module Configuration
class ProviderCollection
extend Rambling::Trie::Forwardable

attr_reader :default, :name

delegate [
:[],
:[]=,
:keys,
:values,
] => :providers

def initialize name, providers = {}, default = nil
@name = name
@configured_providers = providers
@configured_default = default || providers.values.first

reset
end

def add extension, provider
providers[extension] = provider
end

def default= item
if providers.values.any? && !providers.values.include?(item)
raise ArgumentError, "default #{name} should be part of configured #{name}s"
end

@default = item
end

def providers
@providers ||= {}
end

def resolve filepath
providers[format filepath] || default
end

def reset
providers.clear
configured_providers.each { |k, v| providers[k] = v }
self.default = configured_default
end

private

attr_reader :configured_providers, :configured_default

def format filepath
format = File.extname filepath
format.slice! 0
format.to_sym
end
end
end
end
end
37 changes: 37 additions & 0 deletions spec/lib/rambling/trie/configuration/properties_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
require 'spec_helper'

describe Rambling::Trie::Configuration::Properties do
let(:properties) { Rambling::Trie::Configuration::Properties.new }

describe '.new' do
it 'configures the serializers' do
serializers = properties.serializers
expect(serializers.keys).to match_array %i(marshal yaml yml)

expect(serializers[:marshal]).to be_instance_of Rambling::Trie::Serializers::Marshal
expect(serializers[:yaml]).to be_instance_of Rambling::Trie::Serializers::Yaml
expect(serializers[:yml]).to be_instance_of Rambling::Trie::Serializers::Yaml
end

it 'configures the readers' do
readers = properties.readers
expect(readers.keys).to match_array %i(txt)

expect(readers[:txt]).to be_instance_of Rambling::Trie::Readers::PlainText
end
end

describe '#reset' do
before do
properties.serializers.add :test, 'test'
properties.readers.add :test, 'test'

properties.reset
end

it 'resets the serializers and readers to initial values' do
expect(properties.serializers.keys).to match_array %i(marshal yaml yml)
expect(properties.readers.keys).to match_array %i(txt)
end
end
end
143 changes: 143 additions & 0 deletions spec/lib/rambling/trie/configuration/provider_collection_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
require 'spec_helper'

describe Rambling::Trie::Configuration::ProviderCollection do
let(:first_provider) { double :first_provider }
let(:second_provider) { double :second_provider }
let(:default) { nil }

let(:provider_collection) do
Rambling::Trie::Configuration::ProviderCollection.new(
'provider',
{ one: first_provider, two: second_provider },
default
)
end

describe '.new' do
it 'has a name' do
expect(provider_collection.name).to eq 'provider'
end

it 'has the given providers' do
expect(provider_collection.providers)
.to eq one: first_provider, two: second_provider
end

it 'has a default provider' do
expect(provider_collection.default).to eq first_provider
end

context 'when a default is provided' do
let(:default) { second_provider }

it 'has that as the default provider' do
expect(provider_collection.default).to eq second_provider
end
end
end

describe 'aliases and delegates' do
let(:providers) { provider_collection.providers }

before do
allow(providers) .to receive_messages(
:[] => nil,
:[]= => nil,
keys: nil,
values: nil,
)
end

it 'delegates #[] to providers' do
provider_collection[:key]
expect(providers).to have_received(:[]).with :key
end

it 'delegates #[]= to providers' do
provider_collection[:key] = 'hello'
expect(providers).to have_received(:[]=).with :key, 'hello'
end

it 'delegates #keys to providers' do
provider_collection.keys
expect(providers).to have_received :keys
end

it 'delegates #values to providers' do
provider_collection.values
expect(providers).to have_received :values
end
end

describe '#add' do
let(:provider) { double :provider }

before do
provider_collection.add :three, provider
end

it 'adds a new provider' do
expect(provider_collection.providers[:three]).to eq provider
end
end

describe '#default=' do
context 'when the given value is in the providers list' do
it 'changes the default provider' do
provider_collection.default = second_provider
expect(provider_collection.default).to eq second_provider
end
end

context 'when the given value is not in the providers list' do
let(:provider) { double :provider }

it 'does not change the default provider' do
expect do
begin
provider_collection.default = provider
rescue
end
end.not_to change { provider_collection.default }
end

it 'raises an ArgumentError' do
expect do
provider_collection.default = provider
end.to raise_error ArgumentError
end
end
end

describe '#resolve' do
context 'when the file extension is one of the providers' do
it 'returns the corresponding provider' do
expect(provider_collection.resolve 'hola.one').to eq first_provider
expect(provider_collection.resolve 'hola.two').to eq second_provider
end
end

context 'when the file extension is not one of the providers' do
it 'returns the default provider' do
expect(provider_collection.resolve 'hola.unknown').to eq first_provider
expect(provider_collection.resolve 'hola').to eq first_provider
end
end
end

describe '#reset' do
let(:default) { second_provider }
let(:provider) { double :provider }

before do
provider_collection.add :three, provider
provider_collection.default = provider
end

it 'resets to back to the initially configured values' do
provider_collection.reset
expect(provider_collection[:three]).to be_nil
expect(provider_collection.default).to eq second_provider
end
end
end
Loading

0 comments on commit 02e7db2

Please sign in to comment.