/data-provider

Ruby gem that provides a set of classes to build consistent data interfaces

Primary LanguageRubyMIT LicenseMIT

data-provider

Ruby gem that provides a set of classes to build consistent data interfaces

Build Status Code Health

Installation

Rubygems:

gem install data-provider

Bundler:

gem 'data-provider'

Examples

Define a provider class with some providers

require 'data_provider'

class BookProvider
	include DataProvider::Base
	
	# quick syntax for 'simple' providers
	provides({
		title: 'The Monkey Wrench Gang',
		author: 'Edward Abbey'
	})
	
	# longer syntax for more complicated providers
	provider :display_title do
		"#{take(:author)} - #{take(:title)}"
	end

	provider :price do
		9.99
	end
end

Using a provider class

book_provider = BookProvider.new()
book_provider.take(:title) # => 'The Monkey Wrench Gang'
book_provider.take(:author) # => 'Edward Abbey'
book_provider.take(:display_title) # => 'Edward Abbey - The Monkey Wrench Gang'
book_provider.take(:price) # => 9.99

Data providers can be given data to customize their output

require 'data_provider'

class ProductProvider
	include DataProvider::Base
	
	provider :normal_price do
		17.99
	end
	
	provider :discount_price do
		take(:normal_price) - get_data(:discount)
	end
end

product_provider = ProductProvider.new
product_provider.take(:normal_price) # => 17.99
product_provider.take(:discount_price) # => TypeError (discount data not given,): nil can't be coerced into Float
discounted_provider = product_provider.add_data(discount: 3.0) # returns a new instance of the same provider class
discounted_provider.take(:discount_price) # => 14.99
product_provider.take(:discount_price) # => TypeError (this instance didn't get the new data)
product_provider.add_data!(discount: 2) # => Updates this instance instead of creating a new one
product_provider.take(:discount_price) # => 15.99
product_provider.add_data!(discount: 4).take(:discount_price) #=> 13.99

Providers can be defined in a module and added to a provider class using the add class-method (not using include!)

require 'data-provider'

module BandInfo
	include DataProvider::Base
	
	provider :band do
		'D4'
	end
	
	provider :bassPlayer do
		'Paddy'
	end
end

class Band
	include DataProvider::Base
	
	provider :band do
		'Dillinger Four'
	end
	
	provider :drummer do
		'Lane Pederson'
	end

	add BandInfo # note: add, not include!
end

band = Band.new
band.take(:band) # => 'D4', class provider was overwritten when the module got added
band.take(:bassPlayer) # => 'Paddy'
band.take(:drummer) #=> 'Lane Pederson'

Provider identifiers don't have to be symbols, they can be anything. Specifically array identifiers are suitable for creating data providers for hierarchical systems

require 'data_provider'

module AlbumProvider
	include DataProvider::Base
	
	provides({
		title: 'Reinventing Axle Rose',
		band: 'Against Me!'
		[:band, :hometown] => 'Gainesville, FL'
	})
end

class Catalog
	include DataProvider::Base
	
	provider [:music, :album, :bandname] do
		# scoped_take is a method only available inside provider blocks,
		# it lets a provider access other providers in the same 'scope',
		# which means provider whose array-identifiers start with the same values,
		# in this case the scope is [:music, :album]
		scoped_take(:band).upcase
	end

	# by using `add_scoped` all providers of the added module, will be
	# turned into array and prefixed with the given scope
	add_scoped AlbumProvider, :scope => [:music, :album]
end

catalog = Catalog.new
catalog.take(:title) # => DataProvider::ProviderMissingException
catalog.take([:music, :album, :title]) # => 'Reinventing Axle Rose'
catalog.take([:music, :album, :band, :hometown]) # => 'Gainesville, FL'
catalog.take([:music, :album, :bandname]) # => 'AGAINST ME!"