lib/arstotzka/options.rb in arstotzka-1.2.0 vs lib/arstotzka/options.rb in arstotzka-1.2.1
- old
+ new
@@ -2,51 +2,298 @@
module Arstotzka
# @api private
#
# Class responsible to hold the options
+ #
+ # Options is initialized and merged with {DEFAULT_OPTIONS}
+ # when using {ClassMethods#expose}
+ #
+ # @example Using options klass and after
+ # class Customer
+ # attr_reader :name, :age
+ #
+ # def initialize(name:, age:)
+ # @name = name
+ # @age = age
+ # end
+ #
+ # def adult?
+ # age >= 18
+ # end
+ # end
+ #
+ # class Store
+ # include Arstotzka
+ #
+ # expose :customers, klass: Customer, after: :filter_adults
+ #
+ # def initialize(json)
+ # @json = json
+ # end
+ #
+ # private
+ #
+ # attr_reader :json
+ #
+ # def filter_adults(values)
+ # values.select(&:adult?)
+ # end
+ # end
+ #
+ # hash = {
+ # customers: [{
+ # name: 'John', age: 21
+ # }, {
+ # name: 'Julia', age: 15
+ # }, {
+ # name: 'Carol', age: 22
+ # }, {
+ # name: 'Bobby', age: 12
+ # }]
+ # }
+ #
+ # instance = Store.new(hash)
+ #
+ # instance.customers # returns [
+ # # Customer.new(name: 'John', age: 21),
+ # # Customer.new(name: 'Carol', age: 22)
+ # # ]
+ #
+ # @example Using type with klass and after_each
+ # module Arstotzka::TypeCast
+ # def to_symbolized_hash(value)
+ # value.symbolize_keys
+ # end
+ # end
+ #
+ # class Drink
+ # attr_reader :name, :price
+ #
+ # def initialize(name:, price:)
+ # @name = name
+ # @price = price
+ # end
+ #
+ # def inflate(inflation)
+ # @price = (price * (1 + inflation)).round(2)
+ # end
+ # end
+ #
+ # class Bar
+ # include Arstotzka
+ #
+ # expose :drinks, type: :symbolized_hash,
+ # klass: Drink, after_each: :add_inflation
+ #
+ # def initialize(json)
+ # @json = json
+ # end
+ #
+ # private
+ #
+ # attr_reader :json
+ #
+ # def add_inflation(drink)
+ # drink.inflate(0.1)
+ # drink
+ # end
+ # end
+ #
+ # json = '{"drinks":[{"name":"tequila","price":7.50},{ "name":"vodka","price":5.50}]}'
+ #
+ # hash = JSON.parse(hash)
+ #
+ # instance = Bar.new(hash)
+ #
+ # instance.drinks # returns [
+ # # Drink.new(name: 'tequila', price: 8.25),
+ # # Drink.new(name: 'vodka', price: 6.05)
+ # # ]
+ #
+ # @example Using cached, compact, after and full_path
+ # class Person
+ # attr_reader :name
+ #
+ # def initialize(name)
+ # @name = name
+ # end
+ # end
+ #
+ # class Application
+ # include Arstotzka
+ #
+ # expose :users, full_path: 'users.first_name',
+ # compact: true, cached: true,
+ # after: :create_person
+ #
+ # def initialize(json)
+ # @json = json
+ # end
+ #
+ # private
+ #
+ # attr_reader :json
+ #
+ # def create_person(names)
+ # names.map do |name|
+ # warn "Creating person #{name}"
+ # Person.new(name)
+ # end
+ # end
+ # end
+ #
+ # # Keys are on camel case (lower camel case)
+ # hash = {
+ # users: [
+ # { firstName: 'Lucy', email: 'lucy@gmail.com' },
+ # { firstName: 'Bobby', email: 'bobby@hotmail.com' },
+ # { email: 'richard@tracy.com' },
+ # { firstName: 'Arthur', email: 'arthur@kamelot.uk' }
+ # ]
+ # }
+ #
+ # instance = Application.new(hash)
+ #
+ # instance.users # trigers the warn "Creating person <name>" 3 times
+ # # returns [
+ # # Person.new('Lucy'),
+ # # Person.new('Bobby'),
+ # # Person.new('Arthur')
+ # # ]
+ # instance.users # returns the same value, without triggering warn
+ #
+ # @example Working with snake case hash
+ # class JobSeeker
+ # include Arstotzka
+ #
+ # expose :applicants, case: :snake, default: 'John Doe',
+ # full_path: 'applicants.full_name',
+ # compact: true, json: :@hash
+ #
+ # def initialize(hash)
+ # @hash = hash
+ # end
+ # end
+ #
+ # hash = {
+ # 'applicants' => [
+ # {
+ # 'full_name' => 'Robert Hatz',
+ # 'email' => 'robert.hatz@gmail.com'
+ # }, {
+ # 'full_name' => 'Marina Wantz',
+ # 'email' => 'marina.wantz@gmail.com'
+ # }, {
+ # 'email' => 'albert.witz@gmail.com'
+ # }
+ # ]
+ # }
+ #
+ # instance = JobSeeker.new(hash)
+ #
+ # instance.applicants # returns [
+ # # 'Robert Hatz',
+ # # 'Marina Wantz',
+ # # 'John Doe'
+ # # ]
+ #
+ # @example Deep path with flatten option
+ # class ShoppingMall
+ # include Arstotzka
+ #
+ # expose :customers, path: 'floors.stores',
+ # flatten: true, json: :hash
+ #
+ # def initialize(hash)
+ # @hash = hash
+ # end
+ #
+ # private
+ #
+ # attr_reader :hash
+ # end
+ #
+ # hash = {
+ # floors: [{
+ # name: 'ground', stores: [{
+ # name: 'Starbucks', customers: %w[
+ # John Bobby Maria
+ # ]
+ # }, {
+ # name: 'Pizza Hut', customers: %w[
+ # Danny LJ
+ # ]
+ # }]
+ # }, {
+ # name: 'first', stores: [{
+ # name: 'Disney', customers: %w[
+ # Robert Richard
+ # ]
+ # }, {
+ # name: 'Comix', customers: %w[
+ # Linda Ariel
+ # ]
+ # }]
+ # }]
+ # }
+ #
+ # instance = ShoppingMall.new(hash)
+ #
+ # instance.customers # returns %w[
+ # # John Bobby Maria
+ # # Danny LJ Robert Richard
+ # # Linda Ariel
+ # # ]
class Options < ::OpenStruct
DEFAULT_OPTIONS = {
- json: :json,
- path: nil,
- full_path: nil,
- cached: false,
- after: false,
- case: :lower_camel,
- klass: nil,
- compact: false,
- default: nil,
- flatten: false,
- type: :none
+ after: false,
+ after_each: nil,
+ cached: false,
+ case: :lower_camel,
+ compact: false,
+ default: nil,
+ flatten: false,
+ full_path: nil,
+ json: :json,
+ klass: nil,
+ path: nil,
+ type: :none
}.freeze
# Creates a new instance of Options
#
# @param options [Hash] options hash
- # Options hash will be merged with {DEFAULT_OPTIONS}
- # @option options [Class] klass class to receive the methods
- # @option options [String,Symbol] path path of hash attributes to find the root
- # where the attribute live (then fetching it using the attribute name)
- # @option options [String,Symbol] full_path: path of hash attributes to find exacttly where the
- # value live (ignoring the attribute name)
- # @option options [String,Symbol] json: name of the method containing the hash to be crawled
+ #
+ # Options hash are initialized and merged with {DEFAULT_OPTIONS}
+ # when using {ClassMethods#expose}
+ #
+ # @option options [String,Symbol] after: {Fetcher} option with the name of the method to be
+ # called once the value is fetched for mapping the value
+ #
+ # @option options [String,Symbol] after_each: {Wrapper} option with method that will be called
+ # on each individual result (while after is called on the whole collection)
# @option options [Boolean] cached: flag if the result should be memorized instead of repeating
# the crawling
- # @option options [String,Symbol] case: {Reader} flag definining on which case will
+ # @option options [String,Symbol] case: {Reader} flag definining on which case will
# the keys be defined
# - lower_camel: keys in the hash are lowerCamelCase
# - upper_camel: keys in the hash are UpperCamelCase
# - snake: keys in the hash are snake_case
- # @option options [Boolean] compact: {Crawler} flag to apply Array#compact thus
+ # @option options [Boolean] compact: {Crawler} flag to apply Array#compact thus
# removing nil results
- # @option options [Class] klass: {Fetcher} option thatwhen passed, wraps the result in an
- # instance of the given class
- # @option options [String,Symbol] after: {Fetcher} option with the name of the method to be
- # called once the value is fetched for mapping the value
- # @option options [Boolean] flatten: {Fetcher} flag to aplly Array#flatten thus
+ # @option options [Boolean] default: {Crawler} option to return default value instead of nil
+ # @option options [Boolean] flatten: {Fetcher} flag to aplly Array#flatten thus
# avoing nested arrays
+ # @option options [String,Symbol] full_path: path of hash attributes to find exacttly where the
+ # value live (ignoring the attribute name)
+ # @option options [Class] klass: {Fetcher} option that, when passed, wraps the individual
+ # results in an instance of the given class
+ # @option options [String,Symbol] json: name of the method containing the hash to be crawled
+ # @option options [String,Symbol] path path of hash attributes to find the root
+ # where the attribute live (then fetching it using the attribute name)
# @option options [String,Symbol] type: {Fetcher} option declaring the type of the returned
- # value (to use casting)
+ # value (to use casting) (see {TypeCast})
# - integer
# - string
# - float
#
# @see Arstotzka::Options::DEFAULT_OPTIONS