rdl 1.0.0.rc1

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.
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