Project

modelish

0.0
Repository is archived
No commit activity in last 3 years
No release in over 3 years
There's a lot of open issues
Sometimes you need something just a little modelish.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
 Dependencies

Development

Runtime

>= 1.0.0
 Project Readme

modelish

When a real modeling framework is too heavy, sometimes you want something just a little modelish.

IMPORTANT NOTE: modelish is considered legacy code at this point. Maintenance will continue for bug fixes, but active development has ceased. For new projects that require lightweight models, try looking at something like virtus instead.

Overview

If a Hash or OpenStruct almost suits your needs, but you need bits of model-like behavior such as simple validation and typed values, modelish can help.

If you need persistence or anything but the most basic functionality, modelish will frustrate you to no end.

Documentation

See the rdocs.

Installation

modelish is available on Rubygems and can be installed via:

     $ gem install modelish

Basics

Property Types

The modelish syntax is very similar to some of the classes provided by hashie. In fact, the initial implementation simply extended Hashie::Trash to add property types:

    require 'modelish'

    class Foo < Modelish::Base
      property :my_date, :type => Date
      property :my_float, :type => Float, :default => 0.0
      property :my_funky_id, :type => Integer, :from => 'MyFUNKYId'
      property :my_simple_property
    end

You can then set properties as string value and have them automatically converted to the appropriate type, while respecting default values and key-mappings:

   f = Foo.new('MyFUNKYId' => '42', 
               :my_date => '2011-03-10', 
               :my_simple_property => 'bar')

   f.my_date
   # => #<Date: 2011-03-10 (4911261/2,0,2299161)> 
   f.my_float
   # => 0.0 
   f.my_funky_id
   # => 42 
   f.my_simple_property
   # => "bar" 

Property Validation

modelish also supports defining simple property validations:

    class Bar < Modelish::Base
      property :important_field, :required => true
      property :state, :max_length => 2
      property :my_int, :type => Integer, :validate_type => true
      property :another_field, :validator => lambda { |val| "val must respond to []" unless val.respond_to?(:[]) }
    end

Validations can be run using methods that return an error map (keyed on property name), raise errors, or return a boolean value to indicate validation outcome.

    valid_bar = Bar.new(:important_field => 'some value', 
                        :state => 'OR', 
                        :my_int => 42, 
                        :another_field => Hash.new)
    valid_bar.valid?
    # => true

    valid_bar.validate
    # => {}

    valid_bar.validate!
    # => nil


    invalid_bar = Bar.new(:state => 'a value that is too long',
                          :my_int => 'this is not an integer',
                          :another_field => Object.new)
    invalid_bar.valid?
    # => false

    invalid_bar.validate
    # => {:important_field=>[#<ArgumentError: important_field must not be nil or blank>],
    # :my_int=>[#<ArgumentError: my_int must be of type Integer, but got "this is not an integer">],
    # :another_field=>[#<ArgumentError: val must respond to []>], 
    # :state=>[#<ArgumentError: state must be less than 2 characters>]}

    invalid_bar.validate!
    # ArgumentError: important_field must not be nil or blank

In order to implement more complex validations that cannot be accomplished through simple property-specific validators, you may override the validate method. The validate! and valid? methods will continue to work as expected, as long as the overridden validate fulfills the contract (returning a hash keyed on property name, with values being arrays of error objects).

Configuration

By default, modelish will raise an error when it encounters unknown property names in an initialization hash. If you'd prefer modelish to ignore unknown properties, you can override this default behavior for all of your modelish models:

    require 'modelish'

    Modelish.configure do |config|
      config.ignore_unknown_properties = true
    end

    class MyModel < Modelish::Base
      property :foo
    end

    m = MyModel.new(:foo => 'value', :bar => true)
    # => <#MyModel foo="value">

Or you can selectively enable the setting for a particular model:

    require 'modelish'

    class MyPermissiveModel < Modelish::Base
      property :foo
      ignore_unknown_properties!
    end

    class MyStrictModel < Modelish::Base
      property :foo
    end

    p = MyPermissiveModel.new(:foo => 'value', :bar => true)
    # => <#MyPermissiveModel foo="value">

    s = MyStrictModel.new(:foo => 'value', :bar => true)
    # NoMethodError: The property 'bar' is not defined for this Modelish object