SkillAgentSearch skills...

MotionModel

Simple Model and Validation Mixins for RubyMotion

Install / Use

/learn @sxross/MotionModel
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

Code ClimateBuild Status

MotionModel: Models, Relations, and Validation for RubyMotion

MotionModel is a DSL for cases where Core Data is too heavy to lift but you are still intending to work with your data, its types, and its relations. It also provides for data validation and actually quite a bit more.

File | Module | Description ---------------------|---------------------------|------------------------------------ ext.rb | N/A | Core Extensions that provide a few Rails-like niceties. Nothing new here, moving on... model.rb | MotionModel::Model | You should read about it in "What Model Can Do". Model is the raison d'etre and the centerpiece of MotionModel. validatable.rb | MotionModel::Validatable | Provides a basic validation framework for any arbitrary class. You can also create custom validations to suit your app's unique needs. input_helpers | MotionModel::InputHelpers | Helps hook a collection up to a data form, populate the form, and retrieve the data afterwards. Note: MotionModel supports Formotion for input handling as well as these input helpers. formotion.rb | MotionModel::Formotion | Provides an interface between MotionModel and Formotion transaction.rb | MotionModel::Model::Transactions | Provides transaction support for model modifications

MotionModel is MIT licensed, which means you can pretty much do whatever you like with it. See the LICENSE file in this project.

Bugs, Features, and Issues, Oh My!

The reason this is up front here is that in order to respond to your issues we need you to help us out by reading these guidelines. You can also look at Submissions/Patches near the bottom of this README which restates a bit of this.

That said, all software has bugs, and anyone who thinks otherwise probably is smarter than I am. There are going to be edge cases or cases that our tests don't cover. And that's why open source is great: other people will run into issues we can fix. Other people will have needs we don't have but that are of general utility. And so on.

But… fair is fair. We would make the following requests of you:

  • Debug the code as far as you can. Obviously, there are times when you just won't be able to see what's wrong or where there's some squirrely interaction with RubyMotion.
  • If you are comfortable with the MotionModel code, please try to write a spec that makes it fail and submit a pull request with that failing spec. The isolated test case helps us narrow down what changed and to know when we have the issue fixed. Two things make this even better:
    1. Our specs become more comprehensive; and
    2. If the issue is an interaction between MotionModel and RubyMotion, it's easier to pass along to HipByte and have a spec they can use for a quick hitting test case. Even better, fix the bug and submit that fix and the spec in a pull request.
  • If you are not comfortable with the MotionModel code, then go ahead and describe the issue in as much detail as possible, including backtraces from the debugger, if appropriate.

Now, I've belabored the point about bug reporting enough. The point is, if you possibly can, write a spec.

Issues: Please mark your issues as questions or feature requests, depending on which they are. We'll do all we can to review them and answer questions as quickly as possible. For feature requests, you really can implement the feature in many cases and then submit a pull request. If not, we'll leave it open for consideration in future releases.

Summary

Bugs: Please write a failing spec

Issues: Please mark them as question or request

Changes for Existing Users to Be Aware Of

Please see the CHANGELOG for update on changes.

Version 0.4.4 is the first version to be gem-compatible with RubyMotion 2.0

Version 0.3.8 to 0.4.0 is a minor version bump, not a patch version. Upgrading to 0.4.0 will break existing code. To update your code, simply insert the following line:

class ModelWithAdapter
  include MotionModel::Model
  include MotionModel::ArrayModelAdapter # <== Here!

  columns :name
end

This change lays the foundation for using other persistence adapters. If you don't want to update all your models, install the gem:

$ gem install motion_model -v 0.3.8

or if you are using bundler:

gem motion_model, "0.3.8"

Version 0.3.8 was the last that did not separate the model and persistence concerns.

Getting Going

If you are using Bundler, put this in your Gemfile:

gem 'motion_model'

then do:

bundle install

If you are not using Bundler:

gem install motion_model

then put this in your Rakefile after requiring motion/project:

require 'motion_model'

If you want to use Bundler from master, put this in your Gemfile:

gem 'motion_model', :git => 'git@github.com:sxross/MotionModel.git'

Note that in the above construct, Ruby 1.8.x hash keys are used. That's because Apple's System Ruby is 1.8.7 and won't recognize keen new 1.9.x hash syntax.

What MotionModel Can Do

You can define your models and their schemas in Ruby. For example:

class Task
  include MotionModel::Model
  include MotionModel::ArrayModelAdapter

  columns :name        => :string,
          :long_name   => :string,
          :due_date    => :date
end

class MyCoolController
  def some_method
    @task = Task.create :name => 'walk the dog',
                :long_name    => 'get plenty of exercise. pick up the poop',
                :due_date     => '2012-09-15'
   end
end

Side note: The original documentation on this used description for the column that is now long_name. It turns out Apple reserves description so MotionModel saves you the trouble of finding that particular bug by not allowing you to use it for a column name.

Models support default values, so if you specify your model like this, you get defaults:

class Task
  include MotionModel::Model
  include MotionModel::ArrayModelAdapter

  columns :name     => :string,
          :due_date => {:type => :date, :default => '2012-09-15'}
end

A note on defaults, you can specify a proc, block or symbol for your default if you want to get fancy. The most obvious use case for this is that Ruby will optimize the assignment of an array so that a default of [] always points to the same object. Not exactly what is intended. Wrapping this in a proc causes a new array to be created. Here's an example:

class Foo
  include MotionModel::Model
  include MotionModel::ArrayModelAdapter
  columns  subject: { type: :array, default: ->{ [] } }
end

This is not constrained to initializing arrays. You can initialize pretty much anything using a proc or block. If you are specifying a block, make sure to use begin/end instead of do/end because it makes Ruby happy.

Here's a different example:

class Timely
  include MotionModel::Model
  include MotionModel::ArrayModelAdapter
  columns  ended_run_at: { type: :time, default: ->{ Time.now } }
end

Note that this uses the "stubby proc" syntax. That is pretty much equivalent to:

columns  ended_run_at: { type: :time, default: lambda { Time.now } }

for the previous example.

If you want to use a block, use the begin/end syntax:

columns  ended_run_at: { type: :time, default:
  begin
    Time.now
  end
  }

Finally, you can have the default call some class method as follows:

class Timely
  include MotionModel::Model
  include MotionModel::ArrayModelAdapter
  columns  unique_thingie: { type: :integer, default: :randomize }

  def self.randomize
    rand 1_000_000
  end
end

You can also include the Validatable module to get field validation. For example:

class Task
  include MotionModel::Model
  include MotionModel::ArrayModelAdapter
  include MotionModel::Validatable

  columns :name        => :string,
          :long_name   => :string,
          :due_date    => :date
  validates :name, :presence => true
end

class MyCoolController
  def some_method
    @task = Task.new :name  => 'walk the dog',
                 :long_name => 'get plenty of exercise. pick up the poop',
                 :due_date  => '2012-09-15'

    show_scary_warning unless @task.valid?
  end
end

Important Note: Type casting occurs at initialization and on assignment. That means If you have a field type int, it will be changed from a string to an integer when you initialize the object of your class type or when you assign to the integer field in your class.

a_task = Task.create(:name => 'joe-bob', :due_date => '2012-09-15')     # due_date is cast to NSDate

a_task.due_date = '2012-09-19'    # due_date is cast to NSDate

Model Data Types

Currently supported types are:

  • :string
  • :text
  • :boolean, :bool
  • :int, :integer
  • :float, :double
  • :date
  • :array

You are really not encouraged to stuff big things in your models, which is why a blob type is not implemented. The smaller your data, the

View on GitHub
GitHub Stars189
CategoryDevelopment
Updated8mo ago
Forks66

Languages

Ruby

Security Score

87/100

Audited on Jul 22, 2025

No findings