Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

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...
commit 1a7aacbae4e82c6977d8466c46d939e71b3f1a2d 1 parent eee54fe
Clay Allsopp authored May 23, 2012
9  .gitignore
... ...
@@ -1,4 +1,11 @@
1 1
 .repl_history
2 2
 build
3 3
 examples/FacebookGraph/build
4  
-examples/FacebookGraph/vendor
  4
+examples/FacebookGraph/vendor
  5
+resources/*.nib
  6
+resources/*.momd
  7
+resources/*.storyboardc
  8
+*.gem
  9
+.bundle
  10
+Gemfile.lock
  11
+pkg/*
3  .gitmodules
... ...
@@ -1,3 +0,0 @@
1  
-[submodule "vendor/BubbleWrap"]
2  
-	path = vendor/BubbleWrap
3  
-	url = git://github.com/mattetti/BubbleWrap.git
4  Gemfile
... ...
@@ -0,0 +1,4 @@
  1
+source "http://rubygems.org"
  2
+
  3
+# Specify your gem's dependencies in remote_model.gemspec
  4
+gemspec
19  README.md
Source Rendered
@@ -73,25 +73,24 @@ end
73 73
 
74 74
 ## Installation
75 75
 
76  
-Add the git repos as submodules in ./vendor:
77  
-
78  
-```shell
79  
-git submodule add git://github.com/mattetti/BubbleWrap.git ./vendor/BubbleWrap
80  
-git submodule add git://github.com/clayallsopp/remote_model.git ./vendor/remote_model
  76
+```ruby
  77
+gem install remote_model
81 78
 ```
82 79
 
83  
-Then add the lib paths to your ./Rakefile:
  80
+And now in your Rakefile, require `remote_model`:
84 81
 
85 82
 ```ruby
  83
+$:.unshift("/Library/RubyMotion/lib")
  84
+require 'motion/project'
  85
+require 'remote_model'
  86
+
86 87
 Motion::Project::App.setup do |app|
87 88
   ...
88  
-  app.files = Dir.glob(File.join(app.project_dir, 'vendor/BubbleWrap/lib/**/*.rb')) + 
89  
-    Dir.glob(File.join(app.project_dir, 'vendor/remote_model/lib/**/*.rb')) + 
90  
-    app.files
91  
-  ...
92 89
 end
93 90
 ```
94 91
 
  92
+## Setup
  93
+
95 94
 Add an initialization file somewhere, like ./app/initializers/remote_model.rb. This is where we put the API specifications:
96 95
 
97 96
 ```ruby
11  Rakefile
... ...
@@ -1,10 +1 @@
1  
-$:.unshift("/Library/RubyMotion/lib")
2  
-require 'motion/project'
3  
-
4  
-Motion::Project::App.setup do |app|
5  
-  # Use `rake config' to see complete project settings.
6  
-  app.name = 'RemoteModelTestSuite'
7  
-  # via BubbleWrap
8  
-  app.delegate_class = 'TestSuiteDelegate'
9  
-  app.files += Dir.glob(File.join(app.project_dir, 'vendor/BubbleWrap/lib/**/*.rb')) + Dir.glob('./lib/**.rb') 
10  
-end
  1
+require "bundler/gem_tasks"
2  app/app_delegate.rb
... ...
@@ -1,4 +1,4 @@
1  
-class TestSuiteDelegate
  1
+class AppDelegate
2 2
   def application(application, didFinishLaunchingWithOptions:launchOptions)
3 3
     @window = UIWindow.alloc.initWithFrame(UIScreen.mainScreen.bounds)
4 4
     @window.rootViewController = UIViewController.alloc.init
4  examples/FacebookGraph/Rakefile
... ...
@@ -1,13 +1,11 @@
1 1
 $:.unshift("/Library/RubyMotion/lib")
2 2
 require 'motion/project'
3 3
 require 'motion-cocoapods'
  4
+require 'remote_model'
4 5
 
5 6
 Motion::Project::App.setup do |app|
6 7
   # Use `rake config' to see complete project settings.
7 8
   app.name = 'FacebookGraph'
8  
-  app.files = Dir.glob(File.join(app.project_dir, '../../vendor/BubbleWrap/lib/**/*.rb')) + 
9  
-    Dir.glob(File.join(app.project_dir, '../../lib/**/*.rb')) + 
10  
-    app.files
11 9
   app.files_dependencies 'app/controllers/facebook_login_controller.rb' => 'app/initializers/remote_model.rb'
12 10
   fb_app_id = "YOUR-APP-ID"
13 11
   if fb_app_id == "YOUR-APP-ID"
224  lib/remote_model.rb
... ...
@@ -1,218 +1,12 @@
1  
-module RemoteModule
2  
-  class RemoteModel
3  
-    HTTP_METHODS = [:get, :post, :put, :delete]
  1
+require "remote_model/version"
  2
+require "bubble-wrap"
4 3
 
5  
-    class << self
6  
-      # These three methods (has_one/many/ + belongs_to)
7  
-      # map a symbol to a class for method_missing lookup 
8  
-      # for each :symbol in params.
9  
-      # Can also be used to view the current mappings:
10  
-      # EX
11  
-      # Question.has_one
12  
-      # => {:user => User}
  4
+unless defined?(Motion::Project::Config)
  5
+  raise "This file must be required within a RubyMotion project Rakefile."
  6
+end
13 7
 
14  
-      # EX 
15  
-      # self.has_one :question, :answer, :camel_case
16  
-      # => {:question => Question, :answer => Answer, :camel_case => CamelCase}
17  
-      def has_one(params = [])
18  
-        make_fn_lookup "has_one", params, singular_klass_str_lambda
19  
-      end
20  
-
21  
-      # EX 
22  
-      # self.has_many :questions, :answers, :camel_cases
23  
-      # => {:questions => Question, :answers => Answer, :camel_cases => CamelCase}
24  
-      def has_many(params = [])
25  
-        make_fn_lookup "has_many", params, lambda { |sym| sym.to_s.singularize.split("_").collect {|s| s.capitalize}.join }
26  
-      end
27  
-
28  
-      # EX 
29  
-      # self.belongs_to :question, :answer, :camel_case
30  
-      # => {:question => Question, :answer => Answer, :camel_case => CamelCase}
31  
-      def belongs_to(params = [])
32  
-        make_fn_lookup "belongs_to", params, singular_klass_str_lambda
33  
-      end
34  
-
35  
-      def pluralize
36  
-        self.to_s.downcase + "s"
37  
-      end
38  
-
39  
-      def method_missing(method, *args, &block)
40  
-        if self.custom_urls.has_key? method
41  
-          return self.custom_urls[method].format(args && args[0], self)
42  
-        end
43  
-
44  
-        super
45  
-      end
46  
-
47  
-      private
48  
-      # This is kind of neat.
49  
-      # Because models can be mutually dependent (User has a Question, Question has a User),
50  
-      # sometimes RubyMotion hasn't loaded the classes when this is run.
51  
-      # SO we check to see if the class is loaded; if not, then we just add it to the
52  
-      # namespace to make everything run smoothly and assume that by the time the app is running,
53  
-      # all the classes have been loaded.
54  
-      def make_klass(klass_str)
55  
-        begin
56  
-          klass = Object.const_get(klass_str)
57  
-        rescue NameError => e
58  
-          klass = Object.const_set(klass_str, Class.new(RemoteModule::RemoteModel))
59  
-        end
60  
-      end
61  
-
62  
-      def singular_klass_str_lambda
63  
-        lambda { |sym| sym.to_s.split("_").collect {|s| s.capitalize}.join }
64  
-      end
65  
-
66  
-      # How we fake define_method, essentially.
67  
-      # ivar_suffix -> what is the new @ivar called
68  
-      # params -> the :symbols to map to classes
69  
-      # transform -> how we transform the :symbol into a class name
70  
-      def make_fn_lookup(ivar_suffix, params, transform)
71  
-        ivar = "@" + ivar_suffix
72  
-        if !instance_variable_defined? ivar
73  
-          instance_variable_set(ivar, {})
74  
-        end
75  
-        
76  
-        sym_to_klass_sym = {}
77  
-        if params.class == Symbol
78  
-          sym_to_klass_sym[params] = transform.call(params)
79  
-        elsif params.class == Array
80  
-          params.each {|klass_sym|
81  
-            sym_to_klass_sym[klass_sym] = transform.call(klass_sym)
82  
-          }
83  
-        else
84  
-          params.each { |fn_sym, klass_sym| params[fn_sym] = singular_klass_str_lambda.call(klass_sym) }
85  
-          sym_to_klass_sym = params
86  
-        end
87  
-
88  
-        sym_to_klass_sym.each do |relation_sym, klass_sym|
89  
-            klass_str = klass_sym.to_s
90  
-            instance_variable_get(ivar)[relation_sym] = make_klass(klass_str)
91  
-          end
92  
-
93  
-        instance_variable_get(ivar)
94  
-      end
95  
-    end
96  
-
97  
-    def initialize(params = {})
98  
-      update_attributes(params)
99  
-    end
100  
-
101  
-    def update_attributes(params = {})
102  
-      attributes = self.methods - Object.methods
103  
-      params.each do |key, value|
104  
-        if attributes.member?((key.to_s + "=:").to_sym)
105  
-          self.send((key.to_s + "=:").to_sym, value)
106  
-        end
107  
-      end
108  
-    end
109  
-
110  
-    def remote_model_methods
111  
-      methods = []
112  
-      [self.class.has_one, self.class.has_many, self.class.belongs_to].each {|fn_hash|
113  
-        methods += fn_hash.collect {|sym, klass|
114  
-          [sym, (sym.to_s + "=:").to_sym, ("set" + sym.to_s.capitalize).to_sym]
115  
-        }.flatten
116  
-      }
117  
-      methods + RemoteModule::RemoteModel::HTTP_METHODS
118  
-    end
119  
-
120  
-    def methods
121  
-      super + remote_model_methods
122  
-    end
123  
-
124  
-    def respond_to?(symbol, include_private = false)
125  
-      if remote_model_methods.include? symbol
126  
-        return true
127  
-      end
128  
-
129  
-      super
130  
-    end
131  
-
132  
-    def method_missing(method, *args, &block)
133  
-      # Check for custom URLs
134  
-      if self.class.custom_urls.has_key? method
135  
-        return self.class.custom_urls[method].format(args && args[0], self)
136  
-      end
137  
-
138  
-      # has_one relationships
139  
-      if self.class.has_one.has_key?(method) || self.class.belongs_to.has_key?(method)
140  
-        return instance_variable_get("@" + method.to_s)
141  
-      elsif (setter_vals = setter_klass(self.class.has_one, method) || setter_vals = setter_klass(self.class.belongs_to, method))
142  
-        klass, hash_symbol = setter_vals
143  
-        obj = args[0]
144  
-        if obj.class != klass
145  
-          obj = klass.new(obj)
146  
-        end
147  
-        return instance_variable_set("@" + hash_symbol.to_s, obj)
148  
-      end
149  
-
150  
-      # has_many relationships
151  
-      if self.class.has_many.has_key?(method)
152  
-        ivar = "@" + method.to_s
153  
-        if !instance_variable_defined? ivar
154  
-          instance_variable_set(ivar, [])
155  
-        end
156  
-        return instance_variable_get ivar
157  
-      elsif (setter_vals = setter_klass(self.class.has_many, method))
158  
-        klass, hash_symbol = setter_vals
159  
-        ivar = "@" + hash_symbol.to_s
160  
-
161  
-        tmp = []
162  
-        args[0].each do |arg|
163  
-          rep = nil
164  
-          if arg.class == Hash
165  
-            rep = klass.new(arg)
166  
-          elsif arg.class == klass
167  
-            rep = arg
168  
-          end
169  
-
170  
-          if rep.class.belongs_to.values.member? self.class
171  
-            rep.send((rep.class.belongs_to.invert[self.class].to_s + "=").to_sym, self)
172  
-          end
173  
-
174  
-          tmp << rep
175  
-        end
176  
-
177  
-        instance_variable_set(ivar, tmp)
178  
-        return instance_variable_get(ivar)
179  
-      end
180  
-
181  
-      # HTTP methods
182  
-      if RemoteModule::RemoteModel::HTTP_METHODS.member? method
183  
-        return self.class.send(method, *args, &block)
184  
-      end
185  
-
186  
-      super
187  
-    end
188  
-
189  
-    private
190  
-    # PARAMS For a given method symbol, look through the hash
191  
-    #   (which is a map of :symbol => Class)
192  
-    #   and see if that symbol applies to any keys.
193  
-    # RETURNS an array [Klass, symbol] for which the original
194  
-    #   method symbol applies.
195  
-    # EX
196  
-    # setter_klass({:answers => Answer}, :answers=)
197  
-    # => [Answer, :answers]
198  
-    # setter_klass({:answers => Answer}, :setAnswers)
199  
-    # => [Answer, :answers]
200  
-    def setter_klass(hash, symbol)
201  
-
202  
-      # go ahead and guess it's of the form :symbol=:
203  
-      hash_symbol = symbol.to_s[0..-2].to_sym
204  
-
205  
-      # if it's the ObjC style setSymbol, change it to that.
206  
-      if symbol[0..2] == "set"
207  
-        # handles camel case arguments. ex setSomeVariableLikeThis => some_variable_like_this
208  
-        hash_symbol = symbol.to_s[3..-1].split(/([[:upper:]][[:lower:]]*)/).delete_if(&:empty?).map(&:downcase).join("_").to_sym
209  
-      end
210  
-
211  
-      klass = hash[hash_symbol]
212  
-      if klass.nil?
213  
-        return nil
214  
-      end
215  
-      [klass, hash_symbol]
216  
-    end
  8
+Motion::Project::App.setup do |app|
  9
+  Dir.glob(File.join(File.dirname(__FILE__), 'remote_model/*.rb')).each do |file|
  10
+    app.files.unshift(file)
217 11
   end
218  
-end
  12
+end
0  lib/formatable_string.rb → lib/remote_model/formatable_string.rb
File renamed without changes
0  lib/record.rb → lib/remote_model/record.rb
File renamed without changes
218  lib/remote_model/remote_model.rb
... ...
@@ -0,0 +1,218 @@
  1
+module RemoteModule
  2
+  class RemoteModel
  3
+    HTTP_METHODS = [:get, :post, :put, :delete]
  4
+
  5
+    class << self
  6
+      # These three methods (has_one/many/ + belongs_to)
  7
+      # map a symbol to a class for method_missing lookup 
  8
+      # for each :symbol in params.
  9
+      # Can also be used to view the current mappings:
  10
+      # EX
  11
+      # Question.has_one
  12
+      # => {:user => User}
  13
+
  14
+      # EX 
  15
+      # self.has_one :question, :answer, :camel_case
  16
+      # => {:question => Question, :answer => Answer, :camel_case => CamelCase}
  17
+      def has_one(params = [])
  18
+        make_fn_lookup "has_one", params, singular_klass_str_lambda
  19
+      end
  20
+
  21
+      # EX 
  22
+      # self.has_many :questions, :answers, :camel_cases
  23
+      # => {:questions => Question, :answers => Answer, :camel_cases => CamelCase}
  24
+      def has_many(params = [])
  25
+        make_fn_lookup "has_many", params, lambda { |sym| sym.to_s.singularize.split("_").collect {|s| s.capitalize}.join }
  26
+      end
  27
+
  28
+      # EX 
  29
+      # self.belongs_to :question, :answer, :camel_case
  30
+      # => {:question => Question, :answer => Answer, :camel_case => CamelCase}
  31
+      def belongs_to(params = [])
  32
+        make_fn_lookup "belongs_to", params, singular_klass_str_lambda
  33
+      end
  34
+
  35
+      def pluralize
  36
+        self.to_s.downcase + "s"
  37
+      end
  38
+
  39
+      def method_missing(method, *args, &block)
  40
+        if self.custom_urls.has_key? method
  41
+          return self.custom_urls[method].format(args && args[0], self)
  42
+        end
  43
+
  44
+        super
  45
+      end
  46
+
  47
+      private
  48
+      # This is kind of neat.
  49
+      # Because models can be mutually dependent (User has a Question, Question has a User),
  50
+      # sometimes RubyMotion hasn't loaded the classes when this is run.
  51
+      # SO we check to see if the class is loaded; if not, then we just add it to the
  52
+      # namespace to make everything run smoothly and assume that by the time the app is running,
  53
+      # all the classes have been loaded.
  54
+      def make_klass(klass_str)
  55
+        begin
  56
+          klass = Object.const_get(klass_str)
  57
+        rescue NameError => e
  58
+          klass = Object.const_set(klass_str, Class.new(RemoteModule::RemoteModel))
  59
+        end
  60
+      end
  61
+
  62
+      def singular_klass_str_lambda
  63
+        lambda { |sym| sym.to_s.split("_").collect {|s| s.capitalize}.join }
  64
+      end
  65
+
  66
+      # How we fake define_method, essentially.
  67
+      # ivar_suffix -> what is the new @ivar called
  68
+      # params -> the :symbols to map to classes
  69
+      # transform -> how we transform the :symbol into a class name
  70
+      def make_fn_lookup(ivar_suffix, params, transform)
  71
+        ivar = "@" + ivar_suffix
  72
+        if !instance_variable_defined? ivar
  73
+          instance_variable_set(ivar, {})
  74
+        end
  75
+        
  76
+        sym_to_klass_sym = {}
  77
+        if params.class == Symbol
  78
+          sym_to_klass_sym[params] = transform.call(params)
  79
+        elsif params.class == Array
  80
+          params.each {|klass_sym|
  81
+            sym_to_klass_sym[klass_sym] = transform.call(klass_sym)
  82
+          }
  83
+        else
  84
+          params.each { |fn_sym, klass_sym| params[fn_sym] = singular_klass_str_lambda.call(klass_sym) }
  85
+          sym_to_klass_sym = params
  86
+        end
  87
+
  88
+        sym_to_klass_sym.each do |relation_sym, klass_sym|
  89
+            klass_str = klass_sym.to_s
  90
+            instance_variable_get(ivar)[relation_sym] = make_klass(klass_str)
  91
+          end
  92
+
  93
+        instance_variable_get(ivar)
  94
+      end
  95
+    end
  96
+
  97
+    def initialize(params = {})
  98
+      update_attributes(params)
  99
+    end
  100
+
  101
+    def update_attributes(params = {})
  102
+      attributes = self.methods - Object.methods
  103
+      params.each do |key, value|
  104
+        if attributes.member?((key.to_s + "=:").to_sym)
  105
+          self.send((key.to_s + "=:").to_sym, value)
  106
+        end
  107
+      end
  108
+    end
  109
+
  110
+    def remote_model_methods
  111
+      methods = []
  112
+      [self.class.has_one, self.class.has_many, self.class.belongs_to].each {|fn_hash|
  113
+        methods += fn_hash.collect {|sym, klass|
  114
+          [sym, (sym.to_s + "=:").to_sym, ("set" + sym.to_s.capitalize).to_sym]
  115
+        }.flatten
  116
+      }
  117
+      methods + RemoteModule::RemoteModel::HTTP_METHODS
  118
+    end
  119
+
  120
+    def methods
  121
+      super + remote_model_methods
  122
+    end
  123
+
  124
+    def respond_to?(symbol, include_private = false)
  125
+      if remote_model_methods.include? symbol
  126
+        return true
  127
+      end
  128
+
  129
+      super
  130
+    end
  131
+
  132
+    def method_missing(method, *args, &block)
  133
+      # Check for custom URLs
  134
+      if self.class.custom_urls.has_key? method
  135
+        return self.class.custom_urls[method].format(args && args[0], self)
  136
+      end
  137
+
  138
+      # has_one relationships
  139
+      if self.class.has_one.has_key?(method) || self.class.belongs_to.has_key?(method)
  140
+        return instance_variable_get("@" + method.to_s)
  141
+      elsif (setter_vals = setter_klass(self.class.has_one, method) || setter_vals = setter_klass(self.class.belongs_to, method))
  142
+        klass, hash_symbol = setter_vals
  143
+        obj = args[0]
  144
+        if obj.class != klass
  145
+          obj = klass.new(obj)
  146
+        end
  147
+        return instance_variable_set("@" + hash_symbol.to_s, obj)
  148
+      end
  149
+
  150
+      # has_many relationships
  151
+      if self.class.has_many.has_key?(method)
  152
+        ivar = "@" + method.to_s
  153
+        if !instance_variable_defined? ivar
  154
+          instance_variable_set(ivar, [])
  155
+        end
  156
+        return instance_variable_get ivar
  157
+      elsif (setter_vals = setter_klass(self.class.has_many, method))
  158
+        klass, hash_symbol = setter_vals
  159
+        ivar = "@" + hash_symbol.to_s
  160
+
  161
+        tmp = []
  162
+        args[0].each do |arg|
  163
+          rep = nil
  164
+          if arg.class == Hash
  165
+            rep = klass.new(arg)
  166
+          elsif arg.class == klass
  167
+            rep = arg
  168
+          end
  169
+
  170
+          if rep.class.belongs_to.values.member? self.class
  171
+            rep.send((rep.class.belongs_to.invert[self.class].to_s + "=").to_sym, self)
  172
+          end
  173
+
  174
+          tmp << rep
  175
+        end
  176
+
  177
+        instance_variable_set(ivar, tmp)
  178
+        return instance_variable_get(ivar)
  179
+      end
  180
+
  181
+      # HTTP methods
  182
+      if RemoteModule::RemoteModel::HTTP_METHODS.member? method
  183
+        return self.class.send(method, *args, &block)
  184
+      end
  185
+
  186
+      super
  187
+    end
  188
+
  189
+    private
  190
+    # PARAMS For a given method symbol, look through the hash
  191
+    #   (which is a map of :symbol => Class)
  192
+    #   and see if that symbol applies to any keys.
  193
+    # RETURNS an array [Klass, symbol] for which the original
  194
+    #   method symbol applies.
  195
+    # EX
  196
+    # setter_klass({:answers => Answer}, :answers=)
  197
+    # => [Answer, :answers]
  198
+    # setter_klass({:answers => Answer}, :setAnswers)
  199
+    # => [Answer, :answers]
  200
+    def setter_klass(hash, symbol)
  201
+
  202
+      # go ahead and guess it's of the form :symbol=:
  203
+      hash_symbol = symbol.to_s[0..-2].to_sym
  204
+
  205
+      # if it's the ObjC style setSymbol, change it to that.
  206
+      if symbol[0..2] == "set"
  207
+        # handles camel case arguments. ex setSomeVariableLikeThis => some_variable_like_this
  208
+        hash_symbol = symbol.to_s[3..-1].split(/([[:upper:]][[:lower:]]*)/).delete_if(&:empty?).map(&:downcase).join("_").to_sym
  209
+      end
  210
+
  211
+      klass = hash[hash_symbol]
  212
+      if klass.nil?
  213
+        return nil
  214
+      end
  215
+      [klass, hash_symbol]
  216
+    end
  217
+  end
  218
+end
0  lib/requests.rb → lib/remote_model/requests.rb
File renamed without changes
0  lib/string.rb → lib/remote_model/string.rb
File renamed without changes
3  lib/remote_model/version.rb
... ...
@@ -0,0 +1,3 @@
  1
+module RemoteModel
  2
+  VERSION = "0.0.1"
  3
+end
18  remote_model.gemspec
... ...
@@ -0,0 +1,18 @@
  1
+# -*- encoding: utf-8 -*-
  2
+require File.expand_path('../lib/remote_model/version', __FILE__)
  3
+
  4
+Gem::Specification.new do |s|
  5
+  s.name        = "remote_model"
  6
+  s.version     = RemoteModel::VERSION
  7
+  s.authors     = ["Clay Allsopp"]
  8
+  s.email       = ["clay.allsopp@gmail.com"]
  9
+  s.homepage    = "https://github.com/clayallsopp/remote_model"
  10
+  s.summary     = "JSON API <-> NSObject via RubyMotion"
  11
+  s.description = "JSON API <-> NSObject via RubyMotion. Create REST-aware models."
  12
+
  13
+  s.files         = `git ls-files`.split($\)
  14
+  s.test_files    = s.files.grep(%r{^(test|spec|features)/})
  15
+  s.require_paths = ["lib"]
  16
+
  17
+  s.add_dependency "bubble-wrap"
  18
+end
1  vendor/BubbleWrap
... ...
@@ -1 +0,0 @@
1  
-Subproject commit ef429db21e5b90e8fedef75e3453717ef254d402

0 notes on commit 1a7aacb

Please sign in to comment.
Something went wrong with that request. Please try again.