Skip to content

Commit

Permalink
improved query interface, not confirmed stable
Browse files Browse the repository at this point in the history
  • Loading branch information
adelevie committed Sep 2, 2012
2 parents d1af072 + ae242ad commit 8799b13
Show file tree
Hide file tree
Showing 9 changed files with 162 additions and 113 deletions.
2 changes: 1 addition & 1 deletion Gemfile
@@ -1,4 +1,4 @@
source "http://rubygems.org"
source :rubygems

# Specify your gem's dependencies in ParseModel.gemspec
gemspec
3 changes: 1 addition & 2 deletions ParseModel.gemspec
@@ -1,6 +1,5 @@
# -*- encoding: utf-8 -*-
$:.push File.expand_path("../lib", __FILE__)
require "ParseModel/version"
require File.expand_path('../lib/ParseModel/version', __FILE__)

Gem::Specification.new do |s|
s.name = "ParseModel"
Expand Down
22 changes: 15 additions & 7 deletions README.md
Expand Up @@ -2,13 +2,22 @@

ParseModel provides an Active Record pattern to your Parse models on RubyMotion.

I'm using ParseModel internally for a project, slowly but surely making it much, much better. When the project is near completion, I'm going to extract additional functionality into the gem.

Some features to expect:
* Easier queries (`Post.where(:author => @author)`)
* Associations (`class Post; include Parse::Model; has_one :author; end`)
* Overall, a much more Ruby-esque API that still leaves full access to all of the features in the Parse iOS SDK

If you have any questions or suggestions, email me.

## Usage

Create a model:

```ruby
class Post
include Parse::Model
include ParseModel::Model

fields :title, :body, :author
end
Expand All @@ -24,13 +33,13 @@ p.body = "trololol"
p.saveEventually
```

`Parse::Model` objects will `respond_to?` to all methods available to [`PFObject`](https://parse.com/docs/ios/api/Classes/PFObject.html) in the Parse iOS SDK. You can also access the `PFObject` instance directly with, you guessed it, `Parse::Model#PFObject`.
`ParseModel::Model` objects will `respond_to?` to all methods available to [`PFObject`](https://parse.com/docs/ios/api/Classes/PFObject.html) in the Parse iOS SDK. You can also access the `PFObject` instance directly with, you guessed it, `ParseModel::Model#PFObject`.

### Users

```ruby
class User
include Parse::User
include ParseModel::User
end

user = User.new
Expand All @@ -43,7 +52,7 @@ users = User.all # for more User query methods, see: https://parse.com/questions
users.map {|u| u.objectId}.include?(user.objectId) #=> true
```

`Parse::User` delegates to `PFUser` in a very similar fashion as `Parse::Model` delegates to `PFOBject`.
`ParseModel::User` delegates to `PFUser` in a very similar fashion as `ParseModel::Model` delegates to `PFOBject`.

### Queries

Expand All @@ -55,7 +64,7 @@ query.whereKey("title", equalTo:"Why RubyMotion Is Better Than Objective-C")
results = query.findObjects
```

Note that this will return an `Array` of `PFObjects`, not `Parse::Model` objects. To convert, just pass the `PFObject` instance into `Parse::Model#new`:
Note that this will return an `Array` of `PFObjects`, not `ParseModel::Model` objects. To convert, just pass the `PFObject` instance into `ParseModel::Model#new`:

```ruby
results.map! {|result| Post.new(result)}
Expand All @@ -64,8 +73,7 @@ results.map! {|result| Post.new(result)}

## Installation

Either `gem install parse-model` then `require 'ParseModel'` in your `Rakefile`, OR

Either `gem install ParseModel` then `require 'ParseModel'` in your `Rakefile`, OR
`gem "ParseModel"` in your Gemfile. ([Instructions for Bundler setup with Rubymotion)](http://thunderboltlabs.com/posts/using-bundler-with-rubymotion)

Somewhere in your code, such as `app/app_delegate.rb` set your API keys:
Expand Down
5 changes: 4 additions & 1 deletion Rakefile
@@ -1 +1,4 @@
require "bundler/gem_tasks"
$:.unshift("/Library/RubyMotion/lib")
require 'motion/project'
require 'bundler'
Bundler.setup
104 changes: 3 additions & 101 deletions lib/ParseModel.rb
@@ -1,105 +1,7 @@
require "ParseModel/version"

module Parse
module User
attr_accessor :PFUser

RESERVED_KEYS = ['username', 'password', 'email']

def initialize
@PFUser = PFUser.user
end

def method_missing(method, *args, &block)
if RESERVED_KEYS.include?(method)
@PFUser.send(method)
elsif RESERVED_KEYS.map {|f| "#{f}="}.include?("#{method}")
@PFUser.send(method, args.first)
elsif fields.include?(method)
@PFUser.objectForKey(method)
elsif fields.map {|f| "#{f}="}.include?("#{method}")
method = method.split("=")[0]
@PFUser.setObject(args.first, forKey:method)
elsif @PFUser.respond_to?(method)
@PFUser.send(method, *args, &block)
else
super
end
end

def fields
self.class.send(:get_fields)
end

module ClassMethods
def fields(*args)
args.each {|arg| field(arg)}
end

def field(name)
@fields
end

def get_fields
@fields ||= []
@fields
end

def all
query = PFQuery.queryForUser
users = query.findObjects
users
end
end

def self.included(base)
base.extend(ClassMethods)
end

end

module Model
attr_accessor :PFObject

def initialize
@PFObject = PFObject.objectWithClassName(self.class.to_s)
end

def method_missing(method, *args, &block)
if fields.include?(method)
@PFObject.objectForKey(method)
elsif fields.map {|f| "#{f}="}.include?("#{method}")
method = method.split("=")[0]
@PFObject.setObject(args.first, forKey:method)
elsif @PFObject.respond_to?(method)
@PFObject.send(method, *args, &block)
else
super
end
end

def fields
self.class.send(:get_fields)
end

module ClassMethods
def fields(*args)
args.each {|arg| field(arg)}
end

def field(name)
@fields ||= []
@fields << name
end

def get_fields
@fields
end
end

def self.included(base)
base.extend(ClassMethods)
end

Motion::Project::App.setup do |app|
Dir.glob(File.join(File.dirname(__FILE__), "ParseModel/*.rb")).each do |file|
app.files.unshift(file)
end
end
55 changes: 55 additions & 0 deletions lib/ParseModel/Model.rb
@@ -0,0 +1,55 @@
module ParseModel

module Model
attr_accessor :PFObject

def initialize(pf_object=nil)
if pf_object
@PFObject = pf_object
else
@PFObject = PFObject.objectWithClassName(self.class.to_s)
end
end

def method_missing(method, *args, &block)
if fields.include?(method)
@PFObject.objectForKey(method)
elsif fields.map {|f| "#{f}="}.include?("#{method}")
method = method.split("=")[0]
@PFObject.setObject(args.first, forKey:method)
elsif @PFObject.respond_to?(method)
@PFObject.send(method, *args, &block)
else
super
end
end

def fields
self.class.send(:get_fields)
end

module ClassMethods
def fields(*args)
args.each {|arg| field(arg)}
end

def field(name)
@fields ||= []
@fields << name
end

def query
ParseModel::Query.alloc.initWithClassNameAndClassObject(self.name, classObject:self)
end

def get_fields
@fields
end
end

def self.included(base)
base.extend(ClassMethods)
end

end
end
58 changes: 58 additions & 0 deletions lib/ParseModel/User.rb
@@ -0,0 +1,58 @@
module ParseModel
module User
attr_accessor :PFUser

RESERVED_KEYS = ['username', 'password', 'email']

def initialize
@PFUser = PFUser.user
end

def method_missing(method, *args, &block)
if RESERVED_KEYS.include?(method)
@PFUser.send(method)
elsif RESERVED_KEYS.map {|f| "#{f}="}.include?("#{method}")
@PFUser.send(method, args.first)
elsif fields.include?(method)
@PFUser.objectForKey(method)
elsif fields.map {|f| "#{f}="}.include?("#{method}")
method = method.split("=")[0]
@PFUser.setObject(args.first, forKey:method)
elsif @PFUser.respond_to?(method)
@PFUser.send(method, *args, &block)
else
super
end
end

def fields
self.class.send(:get_fields)
end

module ClassMethods
def fields(*args)
args.each {|arg| field(arg)}
end

def field(name)
@fields
end

def get_fields
@fields ||= []
@fields
end

def all
query = PFQuery.queryForUser
users = query.findObjects
users
end
end

def self.included(base)
base.extend(ClassMethods)
end

end
end
24 changes: 24 additions & 0 deletions lib/ParseModel/query.rb
@@ -0,0 +1,24 @@
module ParseModel
class Query < PFQuery

def setClassObject(classObject)
@classObject = classObject
end

def initWithClassNameAndClassObject(className, classObject:myClassObject)
self.initWithClassName(className)
self.setClassObject(myClassObject)
self
end

def find(&block)
return self.findObjects.map {|obj| @classObject.new(obj)} unless block_given?

self.findObjectsInBackgroundWithBlock(lambda do |objects, error|
objects = objects.map {|obj| @classObject.new(obj)} if objects
block.call(objects, error)
end)
end

end
end
2 changes: 1 addition & 1 deletion lib/ParseModel/version.rb
@@ -1,3 +1,3 @@
module ParseModel
VERSION = "0.0.1"
VERSION = "0.0.2"
end

0 comments on commit 8799b13

Please sign in to comment.