Skip to content

Commit

Permalink
Add yard docs
Browse files Browse the repository at this point in the history
  • Loading branch information
DmitryTsepelev committed Aug 7, 2019
1 parent a02383d commit 266fdae
Show file tree
Hide file tree
Showing 18 changed files with 155 additions and 15 deletions.
Binary file added .DS_Store
Binary file not shown.
3 changes: 3 additions & 0 deletions .gitignore
Expand Up @@ -8,3 +8,6 @@ test/dummy/tmp/
Gemfile.lock
Gemfile.local
coverage/

doc/
.yardoc/
3 changes: 0 additions & 3 deletions .rubocop.yml
Expand Up @@ -12,9 +12,6 @@ AllCops:
- 'Gemfile'
- '*.gemspec'

Documentation:
Enabled: false

Style/StringLiterals:
EnforcedStyle: double_quotes

Expand Down
8 changes: 8 additions & 0 deletions lib/active_model/validations/store_model_validator.rb
Expand Up @@ -5,7 +5,15 @@

module ActiveModel
module Validations
# +StoreModelValidator+ is a subclass of ActiveModel::EachValidator for
# checking StoreModel::Model attributes.
class StoreModelValidator < ActiveModel::EachValidator
# Validates _json_ attribute using the configured strategy or
# invalidates _array_ attribute when at least one element is invalid.
#
# @param record [ApplicationRecord] object to validate
# @param attribute [String] name of the validated attribute
# @param value [Object] value of the validated attribute
def validate_each(record, attribute, value)
if value.nil?
record.errors.add(attribute, :blank)
Expand Down
2 changes: 1 addition & 1 deletion lib/store_model.rb
Expand Up @@ -4,7 +4,7 @@
require "store_model/configuration"
require "active_model/validations/store_model_validator"

module StoreModel
module StoreModel # :nodoc:
class << self
def config
@config ||= Configuration.new
Expand Down
7 changes: 6 additions & 1 deletion lib/store_model/combine_errors_strategies.rb
Expand Up @@ -4,10 +4,15 @@
require "store_model/combine_errors_strategies/merge_error_strategy"

module StoreModel
# Module with built-in strategies for combining errors.
module CombineErrorsStrategies
module_function

# Finds a strategy based on options and global config
# Finds a strategy based on +options+ and global config.
#
# @param options [Hash]
#
# @return [Object] strategy
def configure(options)
configured_strategy = options[:merge_errors] || StoreModel.config.merge_errors

Expand Down
Expand Up @@ -2,7 +2,14 @@

module StoreModel
module CombineErrorsStrategies
# +MarkInvalidErrorStrategy+ marks attribute invalid in the parent record.
class MarkInvalidErrorStrategy
# Invalidates +attribute+ in the parent record.
#
# @param attribute [String] name of the validated attribute
# @param base_errors [ActiveModel::Errors] errors object of the parent record
# @param _store_model_errors [ActiveModel::Errors] errors object of the
# StoreModel::Model attribute
def call(attribute, base_errors, _store_model_errors)
base_errors.add(attribute, :invalid)
end
Expand Down
Expand Up @@ -2,7 +2,15 @@

module StoreModel
module CombineErrorsStrategies
# +MergeErrorStrategy+ copies errors from the StoreModel::Model to the parent
# record (for Rails < 6.1) or marks the attribute invalid (for Rails >= 6.1).
class MergeErrorStrategy
# Merges errors on +attribute+ from the child model with parent errors.
#
# @param _attribute [String] name of the validated attribute
# @param base_errors [ActiveModel::Errors] errors object of the parent record
# @param store_model_errors [ActiveModel::Errors] errors object of the StoreModel::Model
# attribute
def call(_attribute, base_errors, store_model_errors)
if Rails::VERSION::MAJOR < 6 || Rails::VERSION::MAJOR == 6 && Rails::VERSION::MINOR.zero?
base_errors.copy!(store_model_errors)
Expand Down
8 changes: 3 additions & 5 deletions lib/store_model/configuration.rb
@@ -1,12 +1,10 @@
# frozen_string_literal: true

module StoreModel
# StoreModel configuration:
#
# - `merge_errors` - set up to `true` to merge errors or specify your
# own strategy
#
# StoreModel configuration.
class Configuration
# Controls usage of MergeErrorStrategy
# @return [Boolean]
attr_accessor :merge_errors
end
end
6 changes: 6 additions & 0 deletions lib/store_model/enum.rb
@@ -1,7 +1,13 @@
# frozen_string_literal: true

module StoreModel
# Allows defining Rails-like enums
module Enum
# Defines new enum
#
# @param name [String] name of the enum to define
# @param values [Object]
# @param kwargs [Object]
def enum(name, values = nil, **kwargs)
values ||= kwargs[:in] || kwargs

Expand Down
35 changes: 33 additions & 2 deletions lib/store_model/model.rb
Expand Up @@ -6,8 +6,9 @@
require "store_model/nested_attributes"

module StoreModel
# When included into class configures it to handle JSON column
module Model
def self.included(base)
def self.included(base) # :nodoc:
base.include ActiveModel::Model
base.include ActiveModel::Attributes
base.include StoreModel::NestedAttributes
Expand All @@ -16,39 +17,69 @@ def self.included(base)
base.extend StoreModel::TypeBuilders
end

# Returns a hash representing the model. Some configuration can be
# passed through +options+.
#
# @param options [Hash]
#
# @return [Hash]
def as_json(options = {})
attributes.with_indifferent_access.as_json(options)
end

# Compares two StoreModel::Model instances
#
# @param other [StoreModel::Model]
#
# @return [Boolean]
def ==(other)
return super unless other.is_a?(self.class)

attributes.all? { |name, value| value == other.send(name) }
end

# Allows to call :presence validation on the association itself
# Allows to call :presence validation on the association itself.
#
# @return [Boolean]
def blank?
attributes.values.all?(&:blank?)
end

# String representation of the object.
#
# @return [String]
def inspect
attribute_string = attributes.map { |name, value| "#{name}: #{value || 'nil'}" }.join(", ")
"#<#{self.class.name} #{attribute_string}>"
end

delegate :attribute_types, to: :class

# Returns the type of the attribute with the given name
#
# @param attr_name [String] name of the attribute
#
# @return [ActiveModel::Type::Value]
def type_for_attribute(attr_name)
attr_name = attr_name.to_s
attribute_types[attr_name]
end

# Checks if the attribute with a given name is defined
#
# @param attr_name [String] name of the attribute
#
# @return [Boolean]
# rubocop:disable Naming/PredicateName
def has_attribute?(attr_name)
attribute_types.key?(attr_name.to_s)
end
# rubocop:enable Naming/PredicateName

# Contains a hash of attributes which are not defined but exist in the
# underlying JSON data
#
# @return [Hash]
def unknown_attributes
@unknown_attributes ||= {}
end
Expand Down
8 changes: 6 additions & 2 deletions lib/store_model/nested_attributes.rb
@@ -1,12 +1,16 @@
# frozen_string_literal: true

module StoreModel
# Contains methods for working with nested StoreModel::Model attributes.
module NestedAttributes
def self.included(base)
def self.included(base) # :nodoc:
base.extend ClassMethods
end

module ClassMethods
module ClassMethods # :nodoc:
# Enables handling of nested StoreModel::Model attributes
#
# @param associations [Array] list of associations to define attributes
def accepts_nested_attributes_for(*associations)
associations.each do |association|
case attribute_types[association.to_s]
Expand Down
5 changes: 5 additions & 0 deletions lib/store_model/type_builders.rb
@@ -1,11 +1,16 @@
# frozen_string_literal: true

module StoreModel
# Contains methods for converting StoreModel::Model to ActiveModel::Type::Value.
module TypeBuilders
# Converts StoreModel::Model to Types::JsonType
# @return [Types::JsonType]
def to_type
Types::JsonType.new(self)
end

# Converts StoreModel::Model to Types::ArrayType
# @return [Types::ArrayType]
def to_array_type
Types::ArrayType.new(self)
end
Expand Down
1 change: 1 addition & 0 deletions lib/store_model/types.rb
Expand Up @@ -5,6 +5,7 @@
require "store_model/types/enum_type"

module StoreModel
# Contains all custom types.
module Types
class CastError < StandardError; end
end
Expand Down
27 changes: 27 additions & 0 deletions lib/store_model/types/array_type.rb
Expand Up @@ -4,15 +4,30 @@

module StoreModel
module Types
# Implements ActiveModel::Type::Value type for handling an array of
# StoreModel::Model
class ArrayType < ActiveModel::Type::Value
# Initializes type for model class
#
# @param model_klass [StoreModel::Model] model class to handle
#
# @return [StoreModel::Types::ArrayType]
def initialize(model_klass)
@model_klass = model_klass
end

# Returns type
#
# @return [Symbol]
def type
:array
end

# Casts +value+ from DB or user to StoreModel::Model instance
#
# @param value [Object] a value to cast
#
# @return StoreModel::Model
def cast_value(value)
case value
when String then decode_and_initialize(value)
Expand All @@ -24,6 +39,12 @@ def cast_value(value)
end
end

# Casts a value from the ruby type to a type that the database knows how
# to understand.
#
# @param value [Object] value to serialize
#
# @return [String] serialized value
def serialize(value)
case value
when Array
Expand All @@ -33,6 +54,12 @@ def serialize(value)
end
end

# Determines whether the mutable value has been modified since it was read
#
# @param raw_old_value [Object] old value
# @param new_value [Object] new value
#
# @return [Boolean]
def changed_in_place?(raw_old_value, new_value)
cast_value(raw_old_value) != new_value
end
Expand Down
14 changes: 14 additions & 0 deletions lib/store_model/types/enum_type.rb
Expand Up @@ -4,15 +4,29 @@

module StoreModel
module Types
# Implements ActiveModel::Type::Value type for handling Rails-like enums
class EnumType < ActiveModel::Type::Value
# Initializes type for mapping
#
# @param mapping [Hash] mapping for enum values
#
# @return [StoreModel::Types::EnumType]
def initialize(mapping)
@mapping = mapping
end

# Returns type
#
# @return [Symbol]
def type
:integer
end

# Casts +value+ from DB or user to StoreModel::Model instance
#
# @param value [Object] a value to cast
#
# @return StoreModel::Model
def cast_value(value)
return if value.blank?

Expand Down
26 changes: 26 additions & 0 deletions lib/store_model/types/json_type.rb
Expand Up @@ -4,15 +4,29 @@

module StoreModel
module Types
# Implements ActiveModel::Type::Value type for handling an instance of StoreModel::Model
class JsonType < ActiveModel::Type::Value
# Initializes type for model class
#
# @param model_klass [StoreModel::Model] model class to handle
#
# @return [StoreModel::Types::JsonType]
def initialize(model_klass)
@model_klass = model_klass
end

# Returns type
#
# @return [Symbol]
def type
:json
end

# Casts +value+ from DB or user to StoreModel::Model instance
#
# @param value [Object] a value to cast
#
# @return StoreModel::Model
def cast_value(value)
case value
when String then decode_and_initialize(value)
Expand All @@ -24,6 +38,12 @@ def cast_value(value)
handle_unknown_attribute(value, e)
end

# Casts a value from the ruby type to a type that the database knows how
# to understand.
#
# @param value [Object] value to serialize
#
# @return [String] serialized value
def serialize(value)
case value
when Hash, @model_klass
Expand All @@ -33,6 +53,12 @@ def serialize(value)
end
end

# Determines whether the mutable value has been modified since it was read
#
# @param raw_old_value [Object] old value
# @param new_value [Object] new value
#
# @return [Boolean]
def changed_in_place?(raw_old_value, new_value)
cast_value(raw_old_value) != new_value
end
Expand Down
2 changes: 1 addition & 1 deletion lib/store_model/version.rb
@@ -1,5 +1,5 @@
# frozen_string_literal: true

module StoreModel
module StoreModel # :nodoc:
VERSION = "0.5.1"
end

0 comments on commit 266fdae

Please sign in to comment.