Browse files

Add gem creation files

./lib -> ./remote_model

remove bubblewrap submodule

fixing copypaste bug

Fix Facebook example to use the gem instead of files

update README for gem
  • Loading branch information...
1 parent eee54fe commit 1a7aacbae4e82c6977d8466c46d939e71b3f1a2d @clayallsopp committed May 23, 2012
View
9 .gitignore
@@ -1,4 +1,11 @@
.repl_history
build
examples/FacebookGraph/build
-examples/FacebookGraph/vendor
+examples/FacebookGraph/vendor
+resources/*.nib
+resources/*.momd
+resources/*.storyboardc
+*.gem
+.bundle
+Gemfile.lock
+pkg/*
View
3 .gitmodules
@@ -1,3 +0,0 @@
-[submodule "vendor/BubbleWrap"]
- path = vendor/BubbleWrap
- url = git://github.com/mattetti/BubbleWrap.git
View
4 Gemfile
@@ -0,0 +1,4 @@
+source "http://rubygems.org"
+
+# Specify your gem's dependencies in remote_model.gemspec
+gemspec
View
19 README.md
@@ -73,25 +73,24 @@ end
## Installation
-Add the git repos as submodules in ./vendor:
-
-```shell
-git submodule add git://github.com/mattetti/BubbleWrap.git ./vendor/BubbleWrap
-git submodule add git://github.com/clayallsopp/remote_model.git ./vendor/remote_model
+```ruby
+gem install remote_model
```
-Then add the lib paths to your ./Rakefile:
+And now in your Rakefile, require `remote_model`:
```ruby
+$:.unshift("/Library/RubyMotion/lib")
+require 'motion/project'
+require 'remote_model'
+
Motion::Project::App.setup do |app|
...
- app.files = Dir.glob(File.join(app.project_dir, 'vendor/BubbleWrap/lib/**/*.rb')) +
- Dir.glob(File.join(app.project_dir, 'vendor/remote_model/lib/**/*.rb')) +
- app.files
- ...
end
```
+## Setup
+
Add an initialization file somewhere, like ./app/initializers/remote_model.rb. This is where we put the API specifications:
```ruby
View
11 Rakefile
@@ -1,10 +1 @@
-$:.unshift("/Library/RubyMotion/lib")
-require 'motion/project'
-
-Motion::Project::App.setup do |app|
- # Use `rake config' to see complete project settings.
- app.name = 'RemoteModelTestSuite'
- # via BubbleWrap
- app.delegate_class = 'TestSuiteDelegate'
- app.files += Dir.glob(File.join(app.project_dir, 'vendor/BubbleWrap/lib/**/*.rb')) + Dir.glob('./lib/**.rb')
-end
+require "bundler/gem_tasks"
View
2 app/app_delegate.rb
@@ -1,4 +1,4 @@
-class TestSuiteDelegate
+class AppDelegate
def application(application, didFinishLaunchingWithOptions:launchOptions)
@window = UIWindow.alloc.initWithFrame(UIScreen.mainScreen.bounds)
@window.rootViewController = UIViewController.alloc.init
View
4 examples/FacebookGraph/Rakefile
@@ -1,13 +1,11 @@
$:.unshift("/Library/RubyMotion/lib")
require 'motion/project'
require 'motion-cocoapods'
+require 'remote_model'
Motion::Project::App.setup do |app|
# Use `rake config' to see complete project settings.
app.name = 'FacebookGraph'
- app.files = Dir.glob(File.join(app.project_dir, '../../vendor/BubbleWrap/lib/**/*.rb')) +
- Dir.glob(File.join(app.project_dir, '../../lib/**/*.rb')) +
- app.files
app.files_dependencies 'app/controllers/facebook_login_controller.rb' => 'app/initializers/remote_model.rb'
fb_app_id = "YOUR-APP-ID"
if fb_app_id == "YOUR-APP-ID"
View
224 lib/remote_model.rb
@@ -1,218 +1,12 @@
-module RemoteModule
- class RemoteModel
- HTTP_METHODS = [:get, :post, :put, :delete]
+require "remote_model/version"
+require "bubble-wrap"
- class << self
- # These three methods (has_one/many/ + belongs_to)
- # map a symbol to a class for method_missing lookup
- # for each :symbol in params.
- # Can also be used to view the current mappings:
- # EX
- # Question.has_one
- # => {:user => User}
+unless defined?(Motion::Project::Config)
+ raise "This file must be required within a RubyMotion project Rakefile."
+end
- # EX
- # self.has_one :question, :answer, :camel_case
- # => {:question => Question, :answer => Answer, :camel_case => CamelCase}
- def has_one(params = [])
- make_fn_lookup "has_one", params, singular_klass_str_lambda
- end
-
- # EX
- # self.has_many :questions, :answers, :camel_cases
- # => {:questions => Question, :answers => Answer, :camel_cases => CamelCase}
- def has_many(params = [])
- make_fn_lookup "has_many", params, lambda { |sym| sym.to_s.singularize.split("_").collect {|s| s.capitalize}.join }
- end
-
- # EX
- # self.belongs_to :question, :answer, :camel_case
- # => {:question => Question, :answer => Answer, :camel_case => CamelCase}
- def belongs_to(params = [])
- make_fn_lookup "belongs_to", params, singular_klass_str_lambda
- end
-
- def pluralize
- self.to_s.downcase + "s"
- end
-
- def method_missing(method, *args, &block)
- if self.custom_urls.has_key? method
- return self.custom_urls[method].format(args && args[0], self)
- end
-
- super
- end
-
- private
- # This is kind of neat.
- # Because models can be mutually dependent (User has a Question, Question has a User),
- # sometimes RubyMotion hasn't loaded the classes when this is run.
- # SO we check to see if the class is loaded; if not, then we just add it to the
- # namespace to make everything run smoothly and assume that by the time the app is running,
- # all the classes have been loaded.
- def make_klass(klass_str)
- begin
- klass = Object.const_get(klass_str)
- rescue NameError => e
- klass = Object.const_set(klass_str, Class.new(RemoteModule::RemoteModel))
- end
- end
-
- def singular_klass_str_lambda
- lambda { |sym| sym.to_s.split("_").collect {|s| s.capitalize}.join }
- end
-
- # How we fake define_method, essentially.
- # ivar_suffix -> what is the new @ivar called
- # params -> the :symbols to map to classes
- # transform -> how we transform the :symbol into a class name
- def make_fn_lookup(ivar_suffix, params, transform)
- ivar = "@" + ivar_suffix
- if !instance_variable_defined? ivar
- instance_variable_set(ivar, {})
- end
-
- sym_to_klass_sym = {}
- if params.class == Symbol
- sym_to_klass_sym[params] = transform.call(params)
- elsif params.class == Array
- params.each {|klass_sym|
- sym_to_klass_sym[klass_sym] = transform.call(klass_sym)
- }
- else
- params.each { |fn_sym, klass_sym| params[fn_sym] = singular_klass_str_lambda.call(klass_sym) }
- sym_to_klass_sym = params
- end
-
- sym_to_klass_sym.each do |relation_sym, klass_sym|
- klass_str = klass_sym.to_s
- instance_variable_get(ivar)[relation_sym] = make_klass(klass_str)
- end
-
- instance_variable_get(ivar)
- end
- end
-
- def initialize(params = {})
- update_attributes(params)
- end
-
- def update_attributes(params = {})
- attributes = self.methods - Object.methods
- params.each do |key, value|
- if attributes.member?((key.to_s + "=:").to_sym)
- self.send((key.to_s + "=:").to_sym, value)
- end
- end
- end
-
- def remote_model_methods
- methods = []
- [self.class.has_one, self.class.has_many, self.class.belongs_to].each {|fn_hash|
- methods += fn_hash.collect {|sym, klass|
- [sym, (sym.to_s + "=:").to_sym, ("set" + sym.to_s.capitalize).to_sym]
- }.flatten
- }
- methods + RemoteModule::RemoteModel::HTTP_METHODS
- end
-
- def methods
- super + remote_model_methods
- end
-
- def respond_to?(symbol, include_private = false)
- if remote_model_methods.include? symbol
- return true
- end
-
- super
- end
-
- def method_missing(method, *args, &block)
- # Check for custom URLs
- if self.class.custom_urls.has_key? method
- return self.class.custom_urls[method].format(args && args[0], self)
- end
-
- # has_one relationships
- if self.class.has_one.has_key?(method) || self.class.belongs_to.has_key?(method)
- return instance_variable_get("@" + method.to_s)
- elsif (setter_vals = setter_klass(self.class.has_one, method) || setter_vals = setter_klass(self.class.belongs_to, method))
- klass, hash_symbol = setter_vals
- obj = args[0]
- if obj.class != klass
- obj = klass.new(obj)
- end
- return instance_variable_set("@" + hash_symbol.to_s, obj)
- end
-
- # has_many relationships
- if self.class.has_many.has_key?(method)
- ivar = "@" + method.to_s
- if !instance_variable_defined? ivar
- instance_variable_set(ivar, [])
- end
- return instance_variable_get ivar
- elsif (setter_vals = setter_klass(self.class.has_many, method))
- klass, hash_symbol = setter_vals
- ivar = "@" + hash_symbol.to_s
-
- tmp = []
- args[0].each do |arg|
- rep = nil
- if arg.class == Hash
- rep = klass.new(arg)
- elsif arg.class == klass
- rep = arg
- end
-
- if rep.class.belongs_to.values.member? self.class
- rep.send((rep.class.belongs_to.invert[self.class].to_s + "=").to_sym, self)
- end
-
- tmp << rep
- end
-
- instance_variable_set(ivar, tmp)
- return instance_variable_get(ivar)
- end
-
- # HTTP methods
- if RemoteModule::RemoteModel::HTTP_METHODS.member? method
- return self.class.send(method, *args, &block)
- end
-
- super
- end
-
- private
- # PARAMS For a given method symbol, look through the hash
- # (which is a map of :symbol => Class)
- # and see if that symbol applies to any keys.
- # RETURNS an array [Klass, symbol] for which the original
- # method symbol applies.
- # EX
- # setter_klass({:answers => Answer}, :answers=)
- # => [Answer, :answers]
- # setter_klass({:answers => Answer}, :setAnswers)
- # => [Answer, :answers]
- def setter_klass(hash, symbol)
-
- # go ahead and guess it's of the form :symbol=:
- hash_symbol = symbol.to_s[0..-2].to_sym
-
- # if it's the ObjC style setSymbol, change it to that.
- if symbol[0..2] == "set"
- # handles camel case arguments. ex setSomeVariableLikeThis => some_variable_like_this
- hash_symbol = symbol.to_s[3..-1].split(/([[:upper:]][[:lower:]]*)/).delete_if(&:empty?).map(&:downcase).join("_").to_sym
- end
-
- klass = hash[hash_symbol]
- if klass.nil?
- return nil
- end
- [klass, hash_symbol]
- end
+Motion::Project::App.setup do |app|
+ Dir.glob(File.join(File.dirname(__FILE__), 'remote_model/*.rb')).each do |file|
+ app.files.unshift(file)
end
-end
+end
View
0 lib/formatable_string.rb → lib/remote_model/formatable_string.rb
File renamed without changes.
View
0 lib/record.rb → lib/remote_model/record.rb
File renamed without changes.
View
218 lib/remote_model/remote_model.rb
@@ -0,0 +1,218 @@
+module RemoteModule
+ class RemoteModel
+ HTTP_METHODS = [:get, :post, :put, :delete]
+
+ class << self
+ # These three methods (has_one/many/ + belongs_to)
+ # map a symbol to a class for method_missing lookup
+ # for each :symbol in params.
+ # Can also be used to view the current mappings:
+ # EX
+ # Question.has_one
+ # => {:user => User}
+
+ # EX
+ # self.has_one :question, :answer, :camel_case
+ # => {:question => Question, :answer => Answer, :camel_case => CamelCase}
+ def has_one(params = [])
+ make_fn_lookup "has_one", params, singular_klass_str_lambda
+ end
+
+ # EX
+ # self.has_many :questions, :answers, :camel_cases
+ # => {:questions => Question, :answers => Answer, :camel_cases => CamelCase}
+ def has_many(params = [])
+ make_fn_lookup "has_many", params, lambda { |sym| sym.to_s.singularize.split("_").collect {|s| s.capitalize}.join }
+ end
+
+ # EX
+ # self.belongs_to :question, :answer, :camel_case
+ # => {:question => Question, :answer => Answer, :camel_case => CamelCase}
+ def belongs_to(params = [])
+ make_fn_lookup "belongs_to", params, singular_klass_str_lambda
+ end
+
+ def pluralize
+ self.to_s.downcase + "s"
+ end
+
+ def method_missing(method, *args, &block)
+ if self.custom_urls.has_key? method
+ return self.custom_urls[method].format(args && args[0], self)
+ end
+
+ super
+ end
+
+ private
+ # This is kind of neat.
+ # Because models can be mutually dependent (User has a Question, Question has a User),
+ # sometimes RubyMotion hasn't loaded the classes when this is run.
+ # SO we check to see if the class is loaded; if not, then we just add it to the
+ # namespace to make everything run smoothly and assume that by the time the app is running,
+ # all the classes have been loaded.
+ def make_klass(klass_str)
+ begin
+ klass = Object.const_get(klass_str)
+ rescue NameError => e
+ klass = Object.const_set(klass_str, Class.new(RemoteModule::RemoteModel))
+ end
+ end
+
+ def singular_klass_str_lambda
+ lambda { |sym| sym.to_s.split("_").collect {|s| s.capitalize}.join }
+ end
+
+ # How we fake define_method, essentially.
+ # ivar_suffix -> what is the new @ivar called
+ # params -> the :symbols to map to classes
+ # transform -> how we transform the :symbol into a class name
+ def make_fn_lookup(ivar_suffix, params, transform)
+ ivar = "@" + ivar_suffix
+ if !instance_variable_defined? ivar
+ instance_variable_set(ivar, {})
+ end
+
+ sym_to_klass_sym = {}
+ if params.class == Symbol
+ sym_to_klass_sym[params] = transform.call(params)
+ elsif params.class == Array
+ params.each {|klass_sym|
+ sym_to_klass_sym[klass_sym] = transform.call(klass_sym)
+ }
+ else
+ params.each { |fn_sym, klass_sym| params[fn_sym] = singular_klass_str_lambda.call(klass_sym) }
+ sym_to_klass_sym = params
+ end
+
+ sym_to_klass_sym.each do |relation_sym, klass_sym|
+ klass_str = klass_sym.to_s
+ instance_variable_get(ivar)[relation_sym] = make_klass(klass_str)
+ end
+
+ instance_variable_get(ivar)
+ end
+ end
+
+ def initialize(params = {})
+ update_attributes(params)
+ end
+
+ def update_attributes(params = {})
+ attributes = self.methods - Object.methods
+ params.each do |key, value|
+ if attributes.member?((key.to_s + "=:").to_sym)
+ self.send((key.to_s + "=:").to_sym, value)
+ end
+ end
+ end
+
+ def remote_model_methods
+ methods = []
+ [self.class.has_one, self.class.has_many, self.class.belongs_to].each {|fn_hash|
+ methods += fn_hash.collect {|sym, klass|
+ [sym, (sym.to_s + "=:").to_sym, ("set" + sym.to_s.capitalize).to_sym]
+ }.flatten
+ }
+ methods + RemoteModule::RemoteModel::HTTP_METHODS
+ end
+
+ def methods
+ super + remote_model_methods
+ end
+
+ def respond_to?(symbol, include_private = false)
+ if remote_model_methods.include? symbol
+ return true
+ end
+
+ super
+ end
+
+ def method_missing(method, *args, &block)
+ # Check for custom URLs
+ if self.class.custom_urls.has_key? method
+ return self.class.custom_urls[method].format(args && args[0], self)
+ end
+
+ # has_one relationships
+ if self.class.has_one.has_key?(method) || self.class.belongs_to.has_key?(method)
+ return instance_variable_get("@" + method.to_s)
+ elsif (setter_vals = setter_klass(self.class.has_one, method) || setter_vals = setter_klass(self.class.belongs_to, method))
+ klass, hash_symbol = setter_vals
+ obj = args[0]
+ if obj.class != klass
+ obj = klass.new(obj)
+ end
+ return instance_variable_set("@" + hash_symbol.to_s, obj)
+ end
+
+ # has_many relationships
+ if self.class.has_many.has_key?(method)
+ ivar = "@" + method.to_s
+ if !instance_variable_defined? ivar
+ instance_variable_set(ivar, [])
+ end
+ return instance_variable_get ivar
+ elsif (setter_vals = setter_klass(self.class.has_many, method))
+ klass, hash_symbol = setter_vals
+ ivar = "@" + hash_symbol.to_s
+
+ tmp = []
+ args[0].each do |arg|
+ rep = nil
+ if arg.class == Hash
+ rep = klass.new(arg)
+ elsif arg.class == klass
+ rep = arg
+ end
+
+ if rep.class.belongs_to.values.member? self.class
+ rep.send((rep.class.belongs_to.invert[self.class].to_s + "=").to_sym, self)
+ end
+
+ tmp << rep
+ end
+
+ instance_variable_set(ivar, tmp)
+ return instance_variable_get(ivar)
+ end
+
+ # HTTP methods
+ if RemoteModule::RemoteModel::HTTP_METHODS.member? method
+ return self.class.send(method, *args, &block)
+ end
+
+ super
+ end
+
+ private
+ # PARAMS For a given method symbol, look through the hash
+ # (which is a map of :symbol => Class)
+ # and see if that symbol applies to any keys.
+ # RETURNS an array [Klass, symbol] for which the original
+ # method symbol applies.
+ # EX
+ # setter_klass({:answers => Answer}, :answers=)
+ # => [Answer, :answers]
+ # setter_klass({:answers => Answer}, :setAnswers)
+ # => [Answer, :answers]
+ def setter_klass(hash, symbol)
+
+ # go ahead and guess it's of the form :symbol=:
+ hash_symbol = symbol.to_s[0..-2].to_sym
+
+ # if it's the ObjC style setSymbol, change it to that.
+ if symbol[0..2] == "set"
+ # handles camel case arguments. ex setSomeVariableLikeThis => some_variable_like_this
+ hash_symbol = symbol.to_s[3..-1].split(/([[:upper:]][[:lower:]]*)/).delete_if(&:empty?).map(&:downcase).join("_").to_sym
+ end
+
+ klass = hash[hash_symbol]
+ if klass.nil?
+ return nil
+ end
+ [klass, hash_symbol]
+ end
+ end
+end
View
0 lib/requests.rb → lib/remote_model/requests.rb
File renamed without changes.
View
0 lib/string.rb → lib/remote_model/string.rb
File renamed without changes.
View
3 lib/remote_model/version.rb
@@ -0,0 +1,3 @@
+module RemoteModel
+ VERSION = "0.0.1"
+end
View
18 remote_model.gemspec
@@ -0,0 +1,18 @@
+# -*- encoding: utf-8 -*-
+require File.expand_path('../lib/remote_model/version', __FILE__)
+
+Gem::Specification.new do |s|
+ s.name = "remote_model"
+ s.version = RemoteModel::VERSION
+ s.authors = ["Clay Allsopp"]
+ s.email = ["clay.allsopp@gmail.com"]
+ s.homepage = "https://github.com/clayallsopp/remote_model"
+ s.summary = "JSON API <-> NSObject via RubyMotion"
+ s.description = "JSON API <-> NSObject via RubyMotion. Create REST-aware models."
+
+ s.files = `git ls-files`.split($\)
+ s.test_files = s.files.grep(%r{^(test|spec|features)/})
+ s.require_paths = ["lib"]
+
+ s.add_dependency "bubble-wrap"
+end
1 vendor/BubbleWrap
@@ -1 +0,0 @@
-Subproject commit ef429db21e5b90e8fedef75e3453717ef254d402

0 comments on commit 1a7aacb

Please sign in to comment.