rdl 1.0.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (89) hide show
  1. checksums.yaml +7 -0
  2. data/lib/rails_types.rb +1 -0
  3. data/lib/rdl.rb +56 -0
  4. data/lib/rdl/config.rb +121 -0
  5. data/lib/rdl/contracts/and.rb +29 -0
  6. data/lib/rdl/contracts/contract.rb +7 -0
  7. data/lib/rdl/contracts/flat.rb +31 -0
  8. data/lib/rdl/contracts/or.rb +25 -0
  9. data/lib/rdl/contracts/proc.rb +24 -0
  10. data/lib/rdl/switch.rb +20 -0
  11. data/lib/rdl/types/annotated_arg.rb +41 -0
  12. data/lib/rdl/types/finitehash.rb +81 -0
  13. data/lib/rdl/types/generic.rb +100 -0
  14. data/lib/rdl/types/intersection.rb +66 -0
  15. data/lib/rdl/types/lexer.rex +39 -0
  16. data/lib/rdl/types/lexer.rex.rb +148 -0
  17. data/lib/rdl/types/method.rb +219 -0
  18. data/lib/rdl/types/nil.rb +50 -0
  19. data/lib/rdl/types/nominal.rb +80 -0
  20. data/lib/rdl/types/optional.rb +54 -0
  21. data/lib/rdl/types/parser.racc +150 -0
  22. data/lib/rdl/types/parser.tab.rb +654 -0
  23. data/lib/rdl/types/singleton.rb +62 -0
  24. data/lib/rdl/types/structural.rb +72 -0
  25. data/lib/rdl/types/top.rb +50 -0
  26. data/lib/rdl/types/tuple.rb +61 -0
  27. data/lib/rdl/types/type.rb +24 -0
  28. data/lib/rdl/types/type_inferencer.rb +73 -0
  29. data/lib/rdl/types/union.rb +74 -0
  30. data/lib/rdl/types/var.rb +51 -0
  31. data/lib/rdl/types/vararg.rb +54 -0
  32. data/lib/rdl/types/wild.rb +26 -0
  33. data/lib/rdl/util.rb +56 -0
  34. data/lib/rdl/wrap.rb +505 -0
  35. data/lib/rdl_types.rb +2 -0
  36. data/types/other/chronic.rb +5 -0
  37. data/types/other/paperclip_attachment.rb +7 -0
  38. data/types/other/securerandom.rb +4 -0
  39. data/types/rails-4.2.1/fixnum.rb +3 -0
  40. data/types/rails-4.2.1/string.rb +3 -0
  41. data/types/rails-tmp/action_dispatch.rb +406 -0
  42. data/types/rails-tmp/active_record.rb +406 -0
  43. data/types/rails-tmp/devise_contracts.rb +216 -0
  44. data/types/ruby-2.2.0/_aliases.rb +4 -0
  45. data/types/ruby-2.2.0/abbrev.rb +5 -0
  46. data/types/ruby-2.2.0/array.rb +137 -0
  47. data/types/ruby-2.2.0/base64.rb +10 -0
  48. data/types/ruby-2.2.0/basic_object.rb +13 -0
  49. data/types/ruby-2.2.0/benchmark.rb +11 -0
  50. data/types/ruby-2.2.0/bigdecimal.rb +15 -0
  51. data/types/ruby-2.2.0/bigmath.rb +12 -0
  52. data/types/ruby-2.2.0/class.rb +17 -0
  53. data/types/ruby-2.2.0/complex.rb +42 -0
  54. data/types/ruby-2.2.0/coverage.rb +6 -0
  55. data/types/ruby-2.2.0/csv.rb +5 -0
  56. data/types/ruby-2.2.0/date.rb +6 -0
  57. data/types/ruby-2.2.0/dir.rb +38 -0
  58. data/types/ruby-2.2.0/encoding.rb +23 -0
  59. data/types/ruby-2.2.0/enumerable.rb +98 -0
  60. data/types/ruby-2.2.0/enumerator.rb +26 -0
  61. data/types/ruby-2.2.0/exception.rb +15 -0
  62. data/types/ruby-2.2.0/file.rb +124 -0
  63. data/types/ruby-2.2.0/fileutils.rb +6 -0
  64. data/types/ruby-2.2.0/fixnum.rb +45 -0
  65. data/types/ruby-2.2.0/float.rb +54 -0
  66. data/types/ruby-2.2.0/gem.rb +245 -0
  67. data/types/ruby-2.2.0/hash.rb +72 -0
  68. data/types/ruby-2.2.0/integer.rb +31 -0
  69. data/types/ruby-2.2.0/io.rb +103 -0
  70. data/types/ruby-2.2.0/kernel.rb +89 -0
  71. data/types/ruby-2.2.0/marshal.rb +5 -0
  72. data/types/ruby-2.2.0/matchdata.rb +26 -0
  73. data/types/ruby-2.2.0/math.rb +53 -0
  74. data/types/ruby-2.2.0/numeric.rb +46 -0
  75. data/types/ruby-2.2.0/object.rb +73 -0
  76. data/types/ruby-2.2.0/pathname.rb +106 -0
  77. data/types/ruby-2.2.0/process.rb +127 -0
  78. data/types/ruby-2.2.0/random.rb +15 -0
  79. data/types/ruby-2.2.0/range.rb +38 -0
  80. data/types/ruby-2.2.0/rational.rb +31 -0
  81. data/types/ruby-2.2.0/regexp.rb +30 -0
  82. data/types/ruby-2.2.0/set.rb +58 -0
  83. data/types/ruby-2.2.0/string.rb +145 -0
  84. data/types/ruby-2.2.0/strscan.rb +7 -0
  85. data/types/ruby-2.2.0/symbol.rb +29 -0
  86. data/types/ruby-2.2.0/time.rb +68 -0
  87. data/types/ruby-2.2.0/uri.rb +18 -0
  88. data/types/ruby-2.2.0/yaml.rb +5 -0
  89. metadata +131 -0
data/lib/rdl_types.rb ADDED
@@ -0,0 +1,2 @@
1
+ require_rel "../types/ruby-#{RUBY_VERSION}/_aliases.rb" # load type aliases first
2
+ require_rel "../types/ruby-#{RUBY_VERSION}/*.rb"
@@ -0,0 +1,5 @@
1
+ module Chronic
2
+ class << self
3
+ type(:parse, "(String) -> ActiveSupport::TimeWithZone")
4
+ end
5
+ end
@@ -0,0 +1,7 @@
1
+ module Paperclip
2
+ end
3
+
4
+ class Paperclip::Attachment
5
+ type(:path, "() -> String")
6
+ type(:path, "(Symbol) -> String")
7
+ end
@@ -0,0 +1,4 @@
1
+ module SecureRandom
2
+ type('self.base64', '(?Fixnum) -> String')
3
+ type('self.hex', '(?Fixnum) -> String')
4
+ end
@@ -0,0 +1,3 @@
1
+ class Fixnum
2
+ type :*, '(ActiveSupport::Duration) -> ActiveSupport::Duration'
3
+ end
@@ -0,0 +1,3 @@
1
+ class String
2
+ type :html_safe, '() -> String'
3
+ end
@@ -0,0 +1,406 @@
1
+ module RailsHelper
2
+ class << self
3
+ attr_accessor :namespace
4
+ attr_accessor :resources_stack
5
+ attr_accessor :inside_member
6
+ end
7
+
8
+ def self.get_path_helper(name)
9
+ stack = RailsHelper.resources_stack.map {|e| e.to_s.singularize}
10
+ resources_str = stack.join("_")
11
+ method_prefix = resources_str == "" ? "#{name}" : "#{name}_#{resources_str}"
12
+ :"#{method_prefix}_path"
13
+ end
14
+
15
+ def self.get_resource_info(controller, action)
16
+ controller_s = controller.singularize
17
+ controller_c = controller_s.camelize
18
+
19
+ case action
20
+ when :new
21
+ v = [/^GET$/]
22
+ p = "/#{controller_s}/new"
23
+ prefix = "#{controller_s}"
24
+ pht = "() -> String"
25
+ when :create
26
+ v = [/^POST$/]
27
+ p = "/#{controller_s}"
28
+ prefix = "#{controller_s}"
29
+ pht = "() -> String"
30
+ when :show
31
+ v = [/^GET$/]
32
+ p = "/#{controller_s}"
33
+ prefix = "#{controller_s}"
34
+ pht = "() -> String"
35
+ when :edit
36
+ v = [/^GET$/]
37
+ p = "/#{controller_s}/edit"
38
+ prefix = "edit_#{controller_s}"
39
+ pht = "() -> String"
40
+ when :update
41
+ v = [/^PUT$/, /^PATCH$/]
42
+ p = "/#{controller_s}"
43
+ prefix = "#{controller_s}"
44
+ pht = "() -> String"
45
+ when :destroy
46
+ v = [/^DELETE$/]
47
+ p = "/#{controller_s}"
48
+ prefix = "#{controller_s}"
49
+ pht = "() -> String"
50
+ else
51
+ raise Exception, "invalid action #{action.inspect}"
52
+ end
53
+
54
+ ph = "#{prefix}_path".to_sym
55
+ uh = "#{prefix}_url".to_sym
56
+ uht = pht
57
+ {:verb => v, :path => p, :path_helper => [ph, pht], :url_helper => [uh, uht]}
58
+ end
59
+
60
+ def self.get_resources_info(controller, action)
61
+ controller_s = controller.singularize
62
+ controller_c = controller_s.camelize
63
+ n = RailsHelper.namespace.to_s
64
+ nnh = (n == "" ? "" : "#{n}_")
65
+
66
+ case action
67
+ when :index
68
+ v = [/^GET$/]
69
+ p = "/#{controller}"
70
+ prefix = "#{nnh}#{controller}"
71
+ pht = "() -> String"
72
+ when :new
73
+ v = [/^GET$/]
74
+ p = "/#{controller}/new"
75
+
76
+ if n == ""
77
+ prefix = "#{controller_s}"
78
+ else
79
+ prefix = "new_#{nnh}#{controller_s}"
80
+ end
81
+
82
+ pht = "() -> String"
83
+ when :create
84
+ v = [/^POST$/]
85
+ p = "/#{controller}"
86
+ prefix = "#{nnh}#{controller}"
87
+ pht = "() -> String"
88
+ when :show
89
+ v = [/^GET$/]
90
+ p = "/#{controller}/:id"
91
+ prefix = "#{nnh}#{controller_s}"
92
+ pht = "(#{controller_c}) -> String"
93
+ when :edit
94
+ v = [/^GET$/]
95
+ p = "/#{controller}/:id/edit"
96
+ prefix = "edit_#{nnh}#{controller_s}"
97
+ pht = "(#{controller_c}) -> String"
98
+ when :update
99
+ v = [/^PUT$/, /^PATCH$/]
100
+ p = "/#{controller}/:id"
101
+ prefix = "#{nnh}#{controller_s}"
102
+ pht = "(#{controller_c}) -> String"
103
+ when :destroy
104
+ v = [/^DELETE$/]
105
+ p = "/#{controller}/:id"
106
+ prefix = "#{nnh}#{controller_s}"
107
+ pht = "(#{controller_c}) -> String"
108
+ else
109
+ raise Exception, "invalid action #{action.inspect}"
110
+ end
111
+
112
+ p = "/#{nnh[0..-2]}#{p}" if nnh != ""
113
+
114
+ ph = "#{prefix}_path".to_sym
115
+ uh = "#{prefix}_url".to_sym
116
+ uht = pht
117
+ {:verb => v, :path => p, :path_helper => [ph, pht], :url_helper => [uh, uht]}
118
+ end
119
+
120
+ def self.resource_routes_info_valid?(routes, controller, action, options={})
121
+ info = get_resource_info(controller, action)
122
+ r_p = info[:path]
123
+ r_v = info[:verb]
124
+
125
+ routes.any? {|r|
126
+ defaults = r.app.instance_variable_get(:@defaults)
127
+ path = r.path.spec.to_s.split('(')[0]
128
+
129
+ if defaults
130
+ defaults[:controller] == controller and defaults[:action] == action.to_s and path == r_p and r_v.include?(r.verb)
131
+ else
132
+ false
133
+ end
134
+ }
135
+ end
136
+
137
+ def self.resources_routes_info_valid?(routes, controller, action, options={})
138
+ info = get_resources_info(controller, action)
139
+ r_p = info[:path]
140
+ r_v = info[:verb]
141
+
142
+ namespace = self.namespace.to_s
143
+ namespace == "" ? c2 = controller : c2 = "#{namespace}/#{controller}"
144
+
145
+ routes.any? {|r|
146
+ defaults = r.app.instance_variable_get(:@defaults)
147
+ path = r.path.spec.to_s.split('(')[0]
148
+
149
+ if defaults
150
+ defaults[:controller] == c2 and defaults[:action] == action.to_s and path == r_p and r_v.include?(r.verb)
151
+ else
152
+ false
153
+ end
154
+ }
155
+ end
156
+
157
+ def self.resource_routes_valid?(routes, resources_args)
158
+ controller = resources_args[0].to_s.pluralize
159
+ controller_obj = controller.pluralize.camelize + "Controller"
160
+ controller_obj = eval(controller_obj)
161
+ options = resources_args[1].nil? ? {} : resources_args[1]
162
+ routes = Rails.application.routes.routes.to_a
163
+
164
+ actions = [:new, :create, :show, :edit, :update, :destroy]
165
+
166
+ if options.keys.include?(:only)
167
+ actions = options[:only]
168
+ elsif options.keys.include?(:except)
169
+ actions = actions - options[:except]
170
+ end
171
+
172
+ r1 = actions.all? {|action|
173
+ resource_routes_info_valid?(routes, controller, action, options)
174
+ }
175
+
176
+ r2 = actions.all? {|action|
177
+ info = get_resource_info(controller, action)
178
+ r_ph = info[:path_helper][0]
179
+ r_uh = info[:url_helper][0]
180
+
181
+ path_helper_added = controller_obj.instance_methods.include?(r_ph)
182
+ url_helper_added = controller_obj.instance_methods.include?(r_uh)
183
+
184
+ path_helper_added and url_helper_added
185
+ }
186
+
187
+ r1 and r2
188
+ end
189
+
190
+ def self.resources_routes_valid?(routes, resources_args)
191
+ controller = resources_args[0].to_s
192
+ controller_obj = controller.camelize + "Controller"
193
+ controller_obj = eval(controller_obj)
194
+ options = resources_args[1].nil? ? {} : resources_args[1]
195
+ routes = Rails.application.routes.routes.to_a
196
+
197
+ actions = [:index, :new, :create, :show, :edit, :update, :destroy]
198
+
199
+ if options.keys.include?(:only)
200
+ actions = options[:only]
201
+ elsif options.keys.include?(:except)
202
+ actions = actions - options[:except]
203
+ end
204
+
205
+ r1 = actions.all? {|action|
206
+ resources_routes_info_valid?(routes, controller, action, options)
207
+ }
208
+
209
+ r2 = actions.all? {|action|
210
+ info = get_resources_info(controller, action)
211
+ r_ph = info[:path_helper][0]
212
+ r_uh = info[:url_helper][0]
213
+
214
+ path_helper_added = controller_obj.instance_methods.include?(r_ph)
215
+ url_helper_added = controller_obj.instance_methods.include?(r_uh)
216
+
217
+ path_helper_added and url_helper_added
218
+ }
219
+
220
+ r1 and r2
221
+ end
222
+ end
223
+
224
+ module ActionDispatch
225
+ module Routing
226
+ class Mapper
227
+ extend RDL
228
+
229
+ spec :root do
230
+ post_cond do |ret, *args|
231
+ methods = [:root_path, :root_url]
232
+
233
+ methods.all? {|m|
234
+ puts "ApplicationController ##% #{m} : () -> String"
235
+
236
+ #add_typesig(ApplicationController, m, "() -> String")
237
+ ApplicationController.instance_methods.include?(m)
238
+ }
239
+ end
240
+ end
241
+
242
+ spec :namespace do
243
+ pre_task do |*args, &blk|
244
+ RailsHelper.namespace = args[0]
245
+ end
246
+
247
+ post_task do |ret, *args, &blk|
248
+ RailsHelper.namespace = nil
249
+ end
250
+ end
251
+
252
+ spec :get do
253
+ pre_cond do |*args, &blk|
254
+ options = args[1] || {}
255
+
256
+ if options.keys.include?(:to)
257
+ if options[:to].class == String
258
+ controller = options[:to].split("#")[0]
259
+ controller = controller.camelize
260
+ action = options[:to].split("#")[1]
261
+
262
+ controller_defined = Object.const_defined?(controller)
263
+
264
+ # TODO: see if action was added. Need late binding?
265
+
266
+ controller_defined
267
+ else
268
+ true
269
+ end
270
+ else
271
+ true
272
+ end
273
+ end
274
+
275
+ post_cond do |ret, *args|
276
+ if RailsHelper.inside_member and not parent_resource.actions.include?(args[0])
277
+ path_helper = RailsHelper.get_path_helper(args[0])
278
+ ctrl = parent_resource.controller.singularize.camelize
279
+
280
+ puts "ApplicationController ##% #{path_helper} : (#{ctrl}) -> String"
281
+
282
+ add_typesig(ApplicationController, path_helper, "() -> String")
283
+
284
+ ApplicationController.instance_methods.include?(path_helper)
285
+ else
286
+ true
287
+ end
288
+ end
289
+ end
290
+
291
+ spec :post do
292
+ post_cond do |ret, *args|
293
+ if RailsHelper.inside_member and not parent_resource.actions.include?(args[0])
294
+ path_helper = RailsHelper.get_path_helper(args[0])
295
+ ctrl = parent_resource.controller.singularize.camelize
296
+
297
+ puts "ApplicationController ##% #{path_helper} : (#{ctrl}) -> String"
298
+
299
+ add_typesig(ApplicationController, path_helper, "() -> String")
300
+
301
+ ApplicationController.instance_methods.include?(path_helper)
302
+ else
303
+ true
304
+ end
305
+ end
306
+ end
307
+
308
+ spec :member do
309
+ pre_task do |*args|
310
+ RailsHelper.inside_member = true
311
+ end
312
+
313
+ post_task do |*args|
314
+ RailsHelper.inside_member = false
315
+ end
316
+ end
317
+
318
+ spec :resource do
319
+ post_task do |ret, *args, &blk|
320
+ return true if args[0] == :session or args[0] == :password or args[0] == :registration or args[0] == :confirmation
321
+
322
+ controller = args[0].to_s
323
+ controller_obj = controller.pluralize.camelize + "Controller"
324
+ controller_obj = eval(controller_obj)
325
+ options = args[1] || {}
326
+ routes = Rails.application.routes.routes.to_a
327
+
328
+ actions = [:new, :create, :show, :edit, :update, :destroy]
329
+
330
+ if options.keys.include?(:only)
331
+ actions = options[:only]
332
+ elsif options.keys.include?(:except)
333
+ actions = actions - options[:except]
334
+ end
335
+
336
+ actions.each {|action|
337
+ info = RailsHelper.get_resource_info(controller, action)
338
+ r_ph = info[:path_helper]
339
+ r_uh = info[:url_helper]
340
+
341
+ #typesig(controller_obj, r_ph[0], r_ph[1])
342
+ #typesig(controller_obj, r_uh[0], r_uh[1])
343
+ }
344
+ end
345
+
346
+ post_cond do |ret, *args, &blk|
347
+ return true if args[0] == :session or args[0] == :password or args[0] == :registration or args[0] == :confirmation
348
+
349
+ model = args[0].to_s
350
+ routes = Rails.application.routes.routes.to_a
351
+
352
+ new_routes_valid = RailsHelper.resource_routes_valid?(routes, args)
353
+
354
+ new_routes_valid
355
+ end
356
+ end
357
+
358
+ # TODO: resources arg can also be a list
359
+ spec :resources do
360
+ pre_task do |*args, &blk|
361
+ RailsHelper.resources_stack = [] if not RailsHelper.resources_stack
362
+ RailsHelper.resources_stack.push(args[0])
363
+ end
364
+
365
+ post_task do |ret, *args, &blk|
366
+ RailsHelper.resources_stack.pop
367
+
368
+ controller = args[0].to_s
369
+ controller_obj = controller.camelize + "Controller"
370
+ controller_obj = eval(controller_obj)
371
+ options = args[1] || {}
372
+ routes = Rails.application.routes.routes.to_a
373
+
374
+ actions = [:index, :new, :create, :show, :edit, :update, :destroy]
375
+
376
+ if options.keys.include?(:only)
377
+ actions = options[:only]
378
+ elsif options.keys.include?(:except)
379
+ actions = actions - options[:except]
380
+ end
381
+
382
+ actions.each {|action|
383
+ info = RailsHelper.get_resources_info(controller, action)
384
+ r_ph = info[:path_helper]
385
+ r_uh = info[:url_helper]
386
+
387
+ puts "#{controller_obj} ##% #{r_ph[0]} : #{r_ph[1]}"
388
+ puts "#{controller_obj} ##% #{r_uh[0]} : #{r_uh[1]}"
389
+
390
+ #typesig(controller_obj, r_ph[0], r_ph[1])
391
+ #typesig(controller_obj, r_uh[0], r_uh[1])
392
+ }
393
+ end
394
+
395
+ post_cond do |ret, *args, &blk|
396
+ model = args[0].to_s
397
+ routes = Rails.application.routes.routes.to_a
398
+
399
+ new_routes_valid = RailsHelper.resources_routes_valid?(routes, args)
400
+
401
+ new_routes_valid
402
+ end
403
+ end
404
+ end
405
+ end
406
+ end
@@ -0,0 +1,406 @@
1
+ module ActiveRecord
2
+ module Associations
3
+ module ClassMethods
4
+ extend RDL
5
+
6
+ def __rdl_get_arg_method_typesig(mname, arg_options)
7
+ if arg_options.keys.include?(:class_name)
8
+ c = arg_options[:class_name]
9
+ else
10
+ c = mname.to_s.singularize.camelize
11
+ end
12
+
13
+ t = "() -> Array<#{c}>"
14
+
15
+ puts "#{self} ##% #{mname} : #{t}"
16
+
17
+ t
18
+ end
19
+
20
+ def __rdl_option_keys_valid?(spec_valid_options, options_used)
21
+ # Original class association options can be found with
22
+ # ActiveRecord::Associations::Builder::Association.valid_options
23
+ # + some more found in ancestors.
24
+
25
+ common_options = [:class_name, :foreign_key, :select, :conditions, :include, :extend, :readonly, :validate, :autosave]
26
+ valid_options = common_options + spec_valid_options
27
+ options_used.keys.all? {|k| valid_options.include?(k)}
28
+ end
29
+
30
+ def __rdl_arg_objects_defined?(arg_name, arg_options)
31
+ if arg_options.keys.include?(:class_name)
32
+ n = arg_options[:class_name]
33
+ else
34
+ n = arg_name.to_s.singularize.camelize
35
+ end
36
+
37
+ r = true
38
+
39
+ if not (arg_options.keys.include?(:polymorphic) and arg_options[:polymorphic] == true)
40
+ begin
41
+ r = eval(n).ancestors.include?(ActiveRecord::Base)
42
+ rescue
43
+ r = false
44
+ end
45
+ end
46
+
47
+ r
48
+
49
+ # TODO: Fix this, late binding?
50
+ true
51
+ end
52
+
53
+ def __rdl_collection_methods_added?(collection, arg_options)
54
+ cstr = collection.to_s
55
+ cstr_s = cstr.singularize
56
+ new_self_methods = [cstr, "#{cstr}=", "#{cstr_s}_ids", "#{cstr_s}_ids="]
57
+ new_self_methods.map! {|m| m.to_sym}
58
+
59
+ # TODO: self.new is ok to call here, but may mutate global state in certain classes
60
+ # The class of self.new is Array here.
61
+
62
+ collection_obj = eval("#{self}.new.#{collection.to_s}")
63
+
64
+ new_collection_methods = [:push, :concat, :build, :create, :create!, :size, :length, :count, :sum, :empty?, :clear, :delete, :delete_all, :destroy_all, :find, :exists?, :uniq, :<<]
65
+ # TODO: reset is also defined on obj, according to the comment in associations.rb
66
+ # but collection_obj.respond(:reset) returns false
67
+ # However, http://guides.rubyonrails.org/association_basics.html does not list :reset
68
+ # as well as several methods from the above as auto-generated methods.
69
+
70
+ methods_added_on_self = new_self_methods.all? {|m|
71
+ self.instance_methods.include?(m)
72
+ }
73
+
74
+ methods_added_on_collection = new_collection_methods.all? {|m|
75
+ collection_obj.respond_to?(m)
76
+ }
77
+
78
+ methods_added_on_self and methods_added_on_collection
79
+
80
+ end
81
+
82
+ def __rdl_singular_methods_added?(type, assoc, arg_options)
83
+ new_methods = {}
84
+
85
+ if arg_options.keys.include?(:class_name)
86
+ cls = arg_options[:class_name]
87
+ else
88
+ cls = assoc.to_s.camelize
89
+ end
90
+
91
+ if type == :belongs_to
92
+ if arg_options.keys.include?(:polymorphic) and arg_options[:polymorphic] == true
93
+ new_methods[:"#{assoc}"] = "(?%bool) -> #{cls}"
94
+ new_methods[:"#{assoc}="] = "(#{cls}) -> #{cls}"
95
+ else
96
+ new_methods[:"#{assoc}"] = "(?%bool) -> #{cls}"
97
+ new_methods[:"#{assoc}="] = "(#{cls}) -> #{cls}"
98
+ new_methods[:"build_#{assoc}"] = "(Hash) -> #{cls}"
99
+ new_methods[:"create_#{assoc}"] = "(Hash) -> #{cls}"
100
+ new_methods[:"create_#{assoc}!"] = "(Hash) -> #{cls}"
101
+ end
102
+ elsif type == :has_one
103
+ new_methods[:"#{assoc}"] = "(?%bool) -> #{cls}"
104
+ new_methods[:"#{assoc}="] = "(#{cls}) -> #{cls}"
105
+ new_methods[:"build_#{assoc}"] = "(Hash) -> #{cls}"
106
+ new_methods[:"create_#{assoc}"] = "(Hash) -> #{cls}"
107
+ new_methods[:"create_#{assoc}!"] = "(Hash) -> #{cls}"
108
+ else
109
+ raise Exception, "type must be a singular association"
110
+ end
111
+
112
+ new_methods.each {|k, v|
113
+ puts "#{self} ##% #{k} : #{v}"
114
+
115
+ #add_typesig(self, k, v)
116
+ }
117
+
118
+ new_methods.keys.all? {|m| self.instance_methods.include?(m)}
119
+ end
120
+
121
+ spec :belongs_to do
122
+ pre_task do |*args|
123
+ $belongs_to_arg_name = args[0]
124
+
125
+ if args.size == 2
126
+ $belongs_to_arg_options = args[1].dup
127
+ else
128
+ $belongs_to_arg_options = {}
129
+ end
130
+
131
+ $belongs_to_self = self
132
+ end
133
+
134
+ pre_cond do |*args|
135
+ $belongs_to_arg_name = args[0]
136
+ arg_name = $belongs_to_arg_name
137
+
138
+ if args.size == 2
139
+ $belongs_to_arg_options = args[1].dup
140
+ else
141
+ $belongs_to_arg_options = {}
142
+ end
143
+
144
+ slf = eval("self")
145
+ arg_options = $belongs_to_arg_options
146
+
147
+ spec_valid_options = [:foreign_type, :polymorphic, :touch, :remote, :dependent, :counter_cache, :primary_key, :inverse_of]
148
+ option_keys_valid = __rdl_option_keys_valid?(spec_valid_options, arg_options)
149
+ arg_classes_defined = __rdl_arg_objects_defined?(arg_name, arg_options)
150
+
151
+ if arg_options.keys.include?(:foreign_key)
152
+ fk = arg_options[:foreign_key]
153
+ else
154
+ fk = "#{arg_name.to_s.underscore}_id"
155
+ end
156
+
157
+ col_names = slf.columns.map {|x| x.name}
158
+ foreign_key_col_exist = col_names.include?(fk)
159
+
160
+ counter_cache_col_exist = true
161
+
162
+ if (arg_options.keys.include?(:counter_cache) and arg_options[:counter_cache]) and not (arg_options.keys.include?(:polymorphic) and arg_options[:polymorphic])
163
+ if arg_options.keys.include?(:class_name)
164
+ assoc = arg_options[:class_name]
165
+ else
166
+ assoc = arg_name.to_s.singularize.camelize
167
+ end
168
+
169
+ assoc_cls = eval(assoc)
170
+ assoc_cols = assoc_cls.columns.map {|x| x.name}
171
+
172
+ # can specify a symbol to override default
173
+ if arg_options[:counter_cache] != true
174
+ cid = arg_options[:counter_cache]
175
+ else
176
+ cid = "#{slf.to_s.pluralize.camelize(:lower)}_count"
177
+ end
178
+
179
+ counter_cache_col_exist = assoc_cols.include?(cid.to_s)
180
+ end
181
+
182
+ option_keys_valid and
183
+ arg_classes_defined and
184
+ foreign_key_col_exist and
185
+ counter_cache_col_exist
186
+ end
187
+
188
+ post_cond do |ret, *args|
189
+ arg_name = $belongs_to_arg_name
190
+ arg_options = $belongs_to_arg_options
191
+ slf = $belongs_to_self
192
+
193
+ correct_methods_added = __rdl_singular_methods_added?(:belongs_to, arg_name, arg_options)
194
+
195
+ if arg_options.keys.include?(:foreign_key)
196
+ fk = arg_options[:foreign_key]
197
+ else
198
+ fk = "#{arg_name.to_s.underscore}_id"
199
+ end
200
+
201
+ foreign_key_added = (slf.reflections.keys.include?(arg_name) and
202
+ (slf.reflections[arg_name].foreign_key == fk))
203
+
204
+ arg_method_added = self.instance_methods.include?(args[0])
205
+ arg_method_typesig = __rdl_get_arg_method_typesig(args[0], arg_options)
206
+
207
+ puts "#{self} ##% #{args[0]} : #{arg_method_typesig}"
208
+ #add_typesig(self, args[0], arg_method_typesig)
209
+
210
+ arg_method_added and correct_methods_added and foreign_key_added
211
+ end
212
+ end
213
+
214
+ spec :has_one do
215
+ pre_task do |*args|
216
+ $has_to_arg_name = args[0]
217
+
218
+ if args.size == 2
219
+ $has_to_arg_options = args[1].dup
220
+ else
221
+ $has_to_arg_options = {}
222
+ end
223
+
224
+ $has_to_self = self
225
+ end
226
+
227
+ pre_cond do |*args|
228
+ $has_one_arg_name = args[0]
229
+ arg_name = $has_one_arg_name
230
+
231
+ if args.size == 2
232
+ $has_one_arg_options = args[1].dup
233
+ else
234
+ $has_one_arg_options = {}
235
+ end
236
+
237
+ slf = eval("self")
238
+ arg_options = $has_one_arg_options
239
+
240
+ spec_valid_options = [:order, :as, :through, :remote, :dependent, :counter_cache, :primary_key, :inverse_of]
241
+ option_keys_valid = __rdl_option_keys_valid?(spec_valid_options, arg_options)
242
+ arg_classes_defined = __rdl_arg_objects_defined?(arg_name, arg_options)
243
+
244
+ option_keys_valid and
245
+ arg_classes_defined
246
+ end
247
+
248
+ post_cond do |ret, *args|
249
+ arg_name = $has_one_arg_name
250
+ arg_options = $has_one_arg_options
251
+ slf = $has_one_self
252
+
253
+ correct_methods_added = __rdl_singular_methods_added?(:has_one, arg_name, arg_options)
254
+
255
+ arg_method_added = self.instance_methods.include?(args[0])
256
+ arg_method_typesig = __rdl_get_arg_method_typesig(args[0], arg_options)
257
+
258
+ puts "#{self} ##% #{args[0]} : #{arg_method_typesig}"
259
+
260
+ arg_method_added and correct_methods_added
261
+ end
262
+ end
263
+
264
+ spec :has_many do
265
+ pre_task do |*args|
266
+ $has_many_arg_name = args[0]
267
+
268
+ if args.size == 2
269
+ $has_many_arg_options = args[1].dup
270
+ else
271
+ $has_many_arg_options = {}
272
+ end
273
+
274
+ $has_many_self = self
275
+ end
276
+
277
+ pre_cond do |*args|
278
+ arg_name = args[0]
279
+
280
+ if args.size == 2
281
+ arg_options = args[1].dup
282
+ else
283
+ arg_options = {}
284
+ end
285
+
286
+ slf = eval("self")
287
+
288
+ spec_valid_options = [:primary_key, :dependent, :as, :through, :source, :source_type, :inverse_of, :table_name, :order, :group, :having, :limit, :offset, :uniq, :finder_sql, :counter_sql, :before_add, :after_add, :before_remove, :after_remove]
289
+ option_keys_valid = __rdl_option_keys_valid?(spec_valid_options, arg_options)
290
+ arg_classes_defined = __rdl_arg_objects_defined?(arg_name, arg_options)
291
+
292
+ option_keys_valid and
293
+ arg_classes_defined
294
+ end
295
+
296
+ post_cond do |ret, *args|
297
+ arg_name = $has_many_arg_name
298
+ arg_options = $has_many_arg_options
299
+ slf = $has_many_self
300
+
301
+ correct_methods_added = __rdl_collection_methods_added?(arg_name, arg_options)
302
+
303
+ if arg_options.keys.include?(:foreign_key)
304
+ fk = arg_options[:foreign_key]
305
+ elsif arg_options.keys.include?(:as)
306
+ fk = arg_options[:as].to_s + "_id"
307
+ elsif arg_options.keys.include?(:class_name)
308
+ fk = arg_options[:class_name].to_s.underscore.camelize(:lower) + "_id"
309
+ else
310
+ fk = "#{slf.to_s.camelize(:lower)}_id"
311
+ end
312
+
313
+ foreign_key_added = (slf.reflections.keys.include?(arg_name) and
314
+ (slf.reflections[arg_name].foreign_key == fk))
315
+
316
+ if arg_options.keys.include?(:foreign_key)
317
+ bad_fk = arg_options[:foreign_key]
318
+ else
319
+ bad_fk = "#{arg_name.to_s.underscore}_id"
320
+ end
321
+
322
+ col_names = slf.columns.map {|x| x.name}
323
+ bad_foreign_key_col_not_exist = (not col_names.include?(fk))
324
+
325
+ arg_method_added = self.instance_methods.include?(args[0])
326
+ arg_method_typesig = __rdl_get_arg_method_typesig(args[0], arg_options)
327
+
328
+ #add_typesig(self, args[0], arg_method_typesig)
329
+
330
+ puts "#{self} ##% #{args[0]} : #{arg_method_typesig}"
331
+
332
+ arg_method_added and
333
+ correct_methods_added and foreign_key_added and
334
+ bad_foreign_key_col_not_exist
335
+ end
336
+ end
337
+
338
+ spec :has_and_belongs_to_many do
339
+ pre_task do |*args|
340
+ $has_and_belongs_to_many_arg_name = args[0]
341
+
342
+ if args.size == 2
343
+ $has_and_belongs_to_many_arg_options = args[1].dup
344
+ else
345
+ $has_and_belongs_to_many_arg_options = {}
346
+ end
347
+
348
+ $has_and_belongs_to_many_self = self
349
+ end
350
+
351
+ pre_cond do |*args|
352
+ $has_and_belongs_to_many_arg_name = args[0]
353
+ arg_name = $has_and_belongs_to_many_arg_name
354
+
355
+ if args.size == 2
356
+ $has_and_belongs_to_many_arg_options = args[1].dup
357
+ else
358
+ $has_and_belongs_to_many_arg_options = {}
359
+ end
360
+
361
+ slf = eval("self")
362
+ arg_options = $has_and_belongs_to_many_arg_options
363
+
364
+ spec_valid_options = [:join_table, :association_foreign_key, :delete_sql, :insert_sql, :table_name, :order, :group, :having, :limit, :offset, :uniq, :finder_sql, :counter_sql, :before_add, :after_add, :before_remove, :after_remove]
365
+ option_keys_valid = __rdl_option_keys_valid?(spec_valid_options, arg_options)
366
+
367
+ arg_classes_defined = __rdl_arg_objects_defined?(arg_name, arg_options)
368
+
369
+ option_keys_valid and
370
+ arg_classes_defined
371
+ end
372
+
373
+ post_cond do |ret, *args|
374
+ arg_name = $has_and_belongs_to_many_arg_name
375
+ arg_options = $has_and_belongs_to_many_arg_options
376
+ slf = $has_and_belongs_to_many_self
377
+
378
+ correct_methods_added = __rdl_collection_methods_added?(arg_name, arg_options)
379
+
380
+ if arg_options.keys.include?(:foreign_key)
381
+ fk = arg_options[:foreign_key]
382
+ elsif arg_options.keys.include?(:as)
383
+ fk = arg_options[:as].to_s + "_id"
384
+ elsif arg_options.keys.include?(:class_name)
385
+ fk = arg_options[:class_name].to_s.underscore.camelize(:lower) + "_id"
386
+ else
387
+ fk = "#{slf.to_s.camelize(:lower)}_id"
388
+ end
389
+
390
+ arg_method_added = self.instance_methods.include?(args[0])
391
+ arg_method_typesig = __rdl_get_arg_method_typesig(args[0], arg_options)
392
+
393
+ # this adds methods like poster_lists, owned_lists, etc
394
+ #add_typesig(self, args[0], arg_method_typesig)
395
+
396
+ puts "#{self} ##% #{args[0]} : #{arg_method_typesig}"
397
+
398
+ foreign_key_added = (slf.reflections.keys.include?(arg_name) and
399
+ (slf.reflections[arg_name].foreign_key == fk))
400
+
401
+ arg_method_added and correct_methods_added and foreign_key_added
402
+ end
403
+ end
404
+ end
405
+ end
406
+ end