rest_kat 0.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/lib/rest_kat.rb ADDED
@@ -0,0 +1,342 @@
1
+ module RestKit
2
+ class Resource
3
+ attr_accessor :hash
4
+ def initialize resource
5
+ self.hash = resource
6
+ end
7
+
8
+ def objc_resource_type
9
+ hash[:type][:name]
10
+ end
11
+
12
+ def objc_class
13
+ "MSRestResource#{hash[:name].camelize}"
14
+ end
15
+
16
+ def permissions
17
+ hash[:permissions]
18
+ end
19
+
20
+ def c_permission_for type
21
+ if permissions.include? type
22
+ "true"
23
+ else
24
+ "false"
25
+ end
26
+ end
27
+
28
+ def singleton?
29
+ @singleton ||= permissions.include? 's'
30
+ end
31
+
32
+ def create?
33
+ @create ||= permissions.include? 'c'
34
+ end
35
+
36
+ def read?
37
+ @read ||= permissions.include? 'r'
38
+ end
39
+
40
+ def update?
41
+ @update ||= permissions.include? 'u'
42
+ end
43
+
44
+ def delete?
45
+ @delete ||= permissions.include? 'd'
46
+ end
47
+
48
+ def queries &block
49
+ if hash.has_key?("queries")
50
+ if block_given?
51
+ hash["queries"].each &block
52
+ else
53
+ hash["queries"]
54
+ end
55
+ else
56
+ []
57
+ end
58
+ end
59
+
60
+ def c_bool r
61
+ if r
62
+ "true"
63
+ else
64
+ "false"
65
+ end
66
+ end
67
+
68
+ end
69
+
70
+ class ObjCProperty
71
+ attr_accessor :klass
72
+ attr_accessor :name
73
+ def initialize(klass, name)
74
+ raise Exception.new(":klass parameter cannot be nil") unless klass
75
+ raise Exception.new(":name parameter cannot be nil") unless name
76
+ self.klass = klass
77
+ self.name = name
78
+ end
79
+ end
80
+
81
+ class ObjCClass
82
+ attr_accessor :properties
83
+ attr_accessor :sequence_of
84
+ attr_accessor :type
85
+ attr_accessor :parent
86
+ attr_accessor :json_type
87
+ attr_accessor :node
88
+ attr_accessor :resource
89
+
90
+ def objc_super_class
91
+ if resource
92
+ "MSRestSerializableResource"
93
+ else
94
+ "MSRestSerializable"
95
+ end
96
+ end
97
+
98
+ def complex?
99
+ map? || seq?
100
+ end
101
+
102
+ def map?
103
+ properties && (not properties.empty?)
104
+ end
105
+
106
+ def seq?
107
+ !!sequence_of
108
+ end
109
+
110
+ def objc_class
111
+ self.type
112
+ end
113
+
114
+ def enum?
115
+ (node["type"] == "str") && node.has_key?("enum")
116
+ end
117
+
118
+ def enum
119
+ node["enum"]
120
+ end
121
+
122
+ def objc_property_decl name
123
+ "@property (nonatomic, strong) #{objc_class} * #{name}"
124
+ end
125
+
126
+ def objc_property_arg_decl name
127
+ "#{name}: (#{objc_class} *) #{name}"
128
+ end
129
+
130
+ def objc_properites_arg_list_decl
131
+ properties.reject{|p| p.name == 'id'}.map do |p|
132
+ p.klass.objc_property_arg_decl p.name
133
+ end.join "\n "
134
+ end
135
+
136
+ def initialize type, json_type, node
137
+ self.properties = nil
138
+ self.type = type
139
+ self.json_type = json_type
140
+ self.node = node
141
+ end
142
+
143
+ end
144
+
145
+ class IosMapping
146
+
147
+ def initialize api_schema
148
+ raise "#{api_schema} does not exist" unless File.exist?(api_schema)
149
+ @schema_file = api_schema
150
+ end
151
+
152
+ def resources_from_schema
153
+ schema[:resources]
154
+ end
155
+
156
+ def schema
157
+ require 'kwalify'
158
+ @schema ||= HashWithIndifferentAccess.new Kwalify::Yaml.load_file(@schema_file)
159
+ end
160
+
161
+ def classes
162
+ @classes ||= []
163
+ end
164
+
165
+ def resources
166
+ @resources ||= []
167
+ end
168
+
169
+ def template name
170
+ require 'erb'
171
+ ERB.new File.read(File.expand_path(File.join("..", name), __FILE__)), 0, '<>'
172
+ end
173
+
174
+ def h_template
175
+ template "model.h.erb"
176
+ end
177
+
178
+ def m_template
179
+ template "model.m.erb"
180
+ end
181
+
182
+ # Generate the required objective c class AST's for th +name+ resource in
183
+ # the correct order so they can be written to code in the correct order in
184
+ # the templates
185
+ def generate_objective_c_classes
186
+ @classes = []
187
+ resources_from_schema.collect do |resource_hash|
188
+ Resource.new(resource_hash).tap do |resource|
189
+ # Generate the query classes first
190
+ resource.queries.each do |query|
191
+ to_objective_c_class query["type"]
192
+ end
193
+ # Generate the resource classes next
194
+ klass = to_objective_c_class resource.hash[:type]
195
+ # Mark this class as being a REST resource
196
+ klass.resource = resource
197
+ end
198
+ end
199
+ end
200
+
201
+ # Generate the objective C header for +name+ resource
202
+ def to_h name
203
+ @resources = generate_objective_c_classes
204
+ h_template.result binding
205
+ end
206
+
207
+ # Generate the objective C implementation file for +name+ resource
208
+ def to_m name
209
+ @resources = generate_objective_c_classes
210
+ #TODO below 'header' must change
211
+ header = (File.basename name, ".*") + ".h"
212
+ m_template.result binding
213
+ end
214
+
215
+ def self.obj_c_type_for_property parent_node, property_name
216
+ parent_type = parent_node[:name].gsub /MSRest/, ''
217
+ "MSRest#{parent_type.camelize}#{property_name.camelize}"
218
+ end
219
+
220
+ def find_processed_class node
221
+ classes.find{|c| c.type == node[:name]}
222
+ end
223
+
224
+ # Perform a depth first traversal of the type tree. The resulting
225
+ # classes array will have the top level class last in the array. In
226
+ # the code generation phase this classes will be injected last into
227
+ # the code making sure the dependencies are define in the correct
228
+ # order.
229
+ def to_objective_c_class node
230
+ unless node
231
+ raise Exception.new("node is nil for name '#{name}'")
232
+ end
233
+
234
+ case node[:type]
235
+ when "map"
236
+
237
+ unless klass = find_processed_class(node)
238
+ klass = ObjCClass.new(node[:name], node[:type], node)
239
+
240
+ klass.properties = node[:mapping].collect do |property_name, property_node|
241
+ if property_node[:type] == "map"
242
+ property_node[:name] ||= IosMapping.obj_c_type_for_property(node, property_name)
243
+ end
244
+ ObjCProperty.new(to_objective_c_class(property_node), property_name)
245
+ end
246
+
247
+ self.classes << klass
248
+ end
249
+
250
+ when "seq"
251
+ klass = ObjCClass.new(node[:name] || "NSArray", node[:type], node)
252
+ if node[:sequence].length != 1
253
+ raise "Only support sequence of map with one map type"
254
+ end
255
+ sequence_node = node[:sequence].first
256
+ if sequence_node["type"] == "map"
257
+ if not sequence_node["name"]
258
+ raise Exception.new ("sequence of map nodes must have a :name to generate the objective C types")
259
+ end
260
+ klass.sequence_of = to_objective_c_class sequence_node
261
+ end
262
+ when "str", "text"
263
+ klass = ObjCClass.new(node[:name] || "NSString", node[:type], node)
264
+ when "int"
265
+ klass = ObjCClass.new(node[:name] || "NSNumber", node[:type], node)
266
+ when "float"
267
+ klass = ObjCClass.new(node[:name] || "NSNumber", node[:type], node)
268
+ when "bool"
269
+ klass = ObjCClass.new(node[:name] || "NSNumber", node[:type], node)
270
+ when "any"
271
+ klass = ObjCClass.new(node[:name] || "NSObject", node[:type], node)
272
+ else
273
+ raise Exception.new("Unhandled type '#{node[:type]} for node with name #{node[:name]}")
274
+ end
275
+
276
+ raise Exception.new("klass cannot be nil") unless klass
277
+
278
+ klass
279
+
280
+ end
281
+ end
282
+ end
283
+
284
+ module RestKat
285
+
286
+ class MySugrIphone
287
+ class <<self
288
+ def root
289
+ ENV["MYSUGR_IPHONE_ROOT"]
290
+ end
291
+ end
292
+ end
293
+
294
+ def self.generate_item(api_location, schema_location, ext)
295
+ deps = %w[
296
+ model.h.erb
297
+ model.m.erb
298
+ rest_kat.rb
299
+ validator.rb
300
+ ].collect do |d|
301
+ File.expand_path "../#{d}", __FILE__
302
+ end
303
+
304
+ deps << schema_location
305
+
306
+ file = "#{api_location}.#{ext}"
307
+
308
+ file_task = Rake::FileTask.define_task file => deps do
309
+ File.open file, 'w' do |f|
310
+ puts "Generating #{file}"
311
+ f.write RestKit::IosMapping.new(schema_location).send("to_#{ext}", file)
312
+ end
313
+ end
314
+ end
315
+
316
+ def self.generate_api(api_location, schema_location)
317
+
318
+ api_src = File.join api_location, "MSRestApiAutoGen"
319
+ m_file_task = generate_item(api_src, schema_location, "h")
320
+ h_file_task = generate_item(api_src, schema_location, "m")
321
+
322
+ src_path = File.expand_path "../../src", __FILE__
323
+
324
+ src_h = File.join src_path, "MSRestSerializable.h"
325
+ src_m = File.join src_path, "MSRestSerializable.m"
326
+
327
+ tgt_h = File.join api_location, "MSRestSerializable.h"
328
+ tgt_m = File.join api_location, "MSRestSerializable.m"
329
+
330
+
331
+ t0 = file tgt_h, src_h do
332
+ cp src_h, tgt_h, :verbose => true
333
+ end
334
+
335
+ t1 = file tgt_m, src_m do
336
+ cp src_m, tgt_m, :verbose => true
337
+ end
338
+
339
+ Rake::Task.define_task :type => [m_file_task, h_file_task, t0, t1]
340
+ end
341
+
342
+ end
File without changes
data/lib/validator.rb ADDED
@@ -0,0 +1,53 @@
1
+ require 'kwalify'
2
+
3
+ module RestKit
4
+ ## validator class for answers
5
+ class Validator < Kwalify::Validator
6
+ ## load schema definition
7
+ @@schema = Kwalify::Yaml.load_file( File.join Rails.root, "lib/rest_kit/api_schema.yml" )
8
+ def self.schema
9
+ @@schema
10
+ end
11
+
12
+ def resource_schema
13
+ @resource_schema
14
+ end
15
+
16
+ def initialize type
17
+ super (@resource_schema=type)
18
+ end
19
+
20
+ def self.find_resource resource
21
+ Validator.schema["resources"].find do |r|
22
+ r["name"].to_s == resource.to_s
23
+ end
24
+ end
25
+
26
+ def self.for_resource resource
27
+ type = find_resource(resource)["type"]
28
+ raise Exception.new("Can't find resource '#{resource}'") unless type
29
+ pp type
30
+ Validator.new type
31
+ end
32
+
33
+ def self.for_type type
34
+ type = Validator.schema[type.to_s]
35
+ raise Exception.new("Can't find resource '#{resource}'") unless type
36
+ pp type
37
+ Validator.new type
38
+ end
39
+
40
+ def self.for_resource_collection resource
41
+ type = find_resource(resource)["type"]
42
+ raise Exception.new("Can't find resource '#{resource}'") unless type
43
+ collection_type = {
44
+ "type" => "seq",
45
+ "sequence" => [ type ]
46
+ }
47
+
48
+ Validator.new collection_type
49
+ end
50
+
51
+ end
52
+
53
+ end
data/rest_kat.gemspec ADDED
@@ -0,0 +1,71 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{rest_kat}
8
+ s.version = "0.0.4"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = [%q{Brad Phelan}]
12
+ s.date = %q{2011-11-18}
13
+ s.description = %q{The generated source code is a layer on top of the iOS REST framework http://restkit.org/}
14
+ s.email = %q{brad.phelan@mysugr.com}
15
+ s.extra_rdoc_files = [
16
+ "LICENSE.txt",
17
+ "README.md",
18
+ "README.rdoc"
19
+ ]
20
+ s.files = [
21
+ ".document",
22
+ ".rspec",
23
+ ".rvmrc",
24
+ "Gemfile",
25
+ "LICENSE.txt",
26
+ "README.md",
27
+ "README.rdoc",
28
+ "Rakefile",
29
+ "VERSION",
30
+ "lib/model.h.erb",
31
+ "lib/model.m.erb",
32
+ "lib/rest_kat.rb",
33
+ "lib/tasks/iphone.rake",
34
+ "lib/validator.rb",
35
+ "rest_kat.gemspec",
36
+ "spec/rest_kat_spec.rb",
37
+ "spec/spec_helper.rb",
38
+ "src/MSRestSerializable.h",
39
+ "src/MSRestSerializable.m"
40
+ ]
41
+ s.homepage = %q{http://github.com/mysugr/rest_kat}
42
+ s.licenses = [%q{MIT}]
43
+ s.require_paths = [%q{lib}]
44
+ s.rubygems_version = %q{1.8.8}
45
+ s.summary = %q{Generate objective C RestKit boilerplate code from a yaml schema}
46
+
47
+ if s.respond_to? :specification_version then
48
+ s.specification_version = 3
49
+
50
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
51
+ s.add_runtime_dependency(%q<kwalify>, [">= 0"])
52
+ s.add_development_dependency(%q<rspec>, ["~> 2.3.0"])
53
+ s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
54
+ s.add_development_dependency(%q<jeweler>, ["~> 1.6.4"])
55
+ s.add_development_dependency(%q<rcov>, [">= 0"])
56
+ else
57
+ s.add_dependency(%q<kwalify>, [">= 0"])
58
+ s.add_dependency(%q<rspec>, ["~> 2.3.0"])
59
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
60
+ s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
61
+ s.add_dependency(%q<rcov>, [">= 0"])
62
+ end
63
+ else
64
+ s.add_dependency(%q<kwalify>, [">= 0"])
65
+ s.add_dependency(%q<rspec>, ["~> 2.3.0"])
66
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
67
+ s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
68
+ s.add_dependency(%q<rcov>, [">= 0"])
69
+ end
70
+ end
71
+
@@ -0,0 +1,7 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe "RestKat" do
4
+ it "fails" do
5
+ fail "hey buddy, you should probably rename this file and start specing for real"
6
+ end
7
+ end
@@ -0,0 +1,12 @@
1
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
3
+ require 'rspec'
4
+ require 'rest_kat'
5
+
6
+ # Requires supporting files with custom matchers and macros, etc,
7
+ # in ./support/ and its subdirectories.
8
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
9
+
10
+ RSpec.configure do |config|
11
+
12
+ end
@@ -0,0 +1,79 @@
1
+ //
2
+ // NSApiBase.h
3
+ // MySugr
4
+ //
5
+ // Created by brad phelan on 10/4/11.
6
+ // Copyright (c) 2011 __MyCompanyName__. All rights reserved.
7
+ //
8
+
9
+ #import <Foundation/Foundation.h>
10
+ #import "NSDate+APIDate.h"
11
+ #import <RestKit/RestKit.h>
12
+
13
+ @interface MSRestSerializable : NSObject<NSCopying>
14
+ // The mapper for this instance
15
+ - (RKObjectMapping *) _mapper;
16
+
17
+ // The serializer for this instance
18
+ - (RKObjectMapping *) _serializer;
19
+
20
+ - (NSDictionary *)convertToDictionary;
21
+
22
+ - (NSString *)convertToFormURLEncoded;
23
+
24
+ - (NSString *)convertToJSON;
25
+
26
+ - (BOOL)isNew;
27
+ @end
28
+
29
+ @interface MSRestSerializableResource : MSRestSerializable
30
+
31
+ #pragma mark methods to be overridden
32
+
33
+ + (Class) classForResource;
34
+
35
+ // The resource path. If this
36
+ + (NSString *) resourcePath;
37
+
38
+ // Is the resource a singleton or a collection
39
+ + (bool) isSingleton;
40
+
41
+ // Can the client create resources
42
+ + (bool) canCreate;
43
+
44
+ // Can the client read resources
45
+ + (bool) canRead;
46
+
47
+ // Can the client update resources
48
+ + (bool) canUpdate;
49
+
50
+ // Can the client delete resources
51
+ + (bool) canDelete;
52
+
53
+ #pragma mark helpers
54
+
55
+ // The router for this class
56
+ + (RKObjectRouter *) router;
57
+
58
+ // Intialize the routing module. Must
59
+ // be called from +initialize in a
60
+ // subclass or the logic will not
61
+ // work.
62
+ + (void) initializeRouting;
63
+
64
+
65
+ // save the object
66
+ -(void) saveWithDelegate:(id<RKObjectLoaderDelegate>)delegate;
67
+
68
+ // Find an instance by id
69
+ + (void) find:(NSNumber *)id
70
+ withDelegate:(id<RKObjectLoaderDelegate>)delegate;
71
+
72
+ // Load collection
73
+ + (void) loadCollectionWithDelegate:(id<RKObjectLoaderDelegate>)delegate;
74
+
75
+ // Load collection with query
76
+ + (void) loadCollectionThroughQuery:(MSRestSerializable *)mappableQueryObject
77
+ withDelegate:(id<RKObjectLoaderDelegate>)delegate;
78
+
79
+ @end