active_doc 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,48 @@
1
+ require 'active_doc'
2
+
3
+ module ActiveDoc
4
+ module Rake
5
+ # Defines a Rake tasks for generating RDoc documentation from active_doc.
6
+ # User proc to load files you want to generate RDoc for.
7
+ #
8
+ # The simplest use of it goes something like:
9
+ #
10
+ # ActiveDoc::Rake::Task.new do
11
+ # require 'file_one.rb' # files you want to describe
12
+ # require 'file_two.rb'
13
+ # end
14
+ #
15
+ #
16
+ # This will define a task named <tt>active_doc</tt> described as 'Generate ActiveDoc RDoc documentation'.
17
+ class Task
18
+ class GenerateRDocRunner #:nodoc:
19
+
20
+ def initialize
21
+ end
22
+
23
+ def run
24
+ ActiveDoc::RdocGenerator.write_rdoc do |file, documented_methods|
25
+ STDOUT.puts "Generating RDoc for #{file}..."
26
+ end
27
+ end
28
+ end
29
+
30
+ def initialize(task_name = "active_doc", desc = "Generate ActiveDoc RDoc documentation")
31
+ @task_name, @desc = task_name, desc
32
+ yield self if block_given?
33
+ define_task
34
+ end
35
+
36
+ def define_task #:nodoc:
37
+ desc @desc
38
+ task @task_name do
39
+ runner.run
40
+ end
41
+ end
42
+
43
+ def runner #:nodoc:
44
+ GenerateRDocRunner.new
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,21 @@
1
+ module ActiveDoc
2
+ class RdocGenerator
3
+ def self.for_method(base, method_name)
4
+ if documented_method = ActiveDoc.documented_method(base, method_name)
5
+ documented_method.to_rdoc
6
+ end
7
+ end
8
+
9
+ def self.write_rdoc(source_file_path = nil)
10
+ files_and_methods = ActiveDoc.documented_methods.sort_by { |x| x.origin_line }.group_by { |x| x.origin_file }
11
+ files_and_methods.delete_if { |file| file != source_file_path } if source_file_path
12
+ files_and_methods.each do |origin_file, documented_methods|
13
+ offset = 0
14
+ yield origin_file, documented_methods if block_given?
15
+ documented_methods.each do |documented_method|
16
+ offset = documented_method.write_rdoc(offset)
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,341 @@
1
+ require 'spec_helper'
2
+ class PhoneBook
3
+ include ActiveDoc
4
+ attr_accessor :owner
5
+
6
+ def initialize(owner)
7
+ @numbers = []
8
+ PhoneBook.register(self)
9
+ end
10
+
11
+ takes :contact_name, String
12
+ def add(contact_name, number)
13
+ @numbers << [contact_name, number]
14
+ end
15
+
16
+ takes :owner, String
17
+ def self.find_for_owner(owner)
18
+ @phone_books && @phone_books[owner]
19
+ end
20
+
21
+ class << self
22
+ takes :phone_book, PhoneBook
23
+ def register(phone_book)
24
+ @phone_books ||= {}
25
+ @phone_books[phone_book.owner] = phone_book
26
+ end
27
+ end
28
+
29
+ def self.phone_books
30
+ return @phone_books.values
31
+ end
32
+
33
+ def size
34
+ return @numbers.size
35
+ end
36
+ end
37
+
38
+ describe ActiveDoc::Descriptions::MethodArgumentDescription do
39
+ describe "more described methods" do
40
+ subject { PhoneBook.new("Peter Smith") }
41
+ context "instance method" do
42
+ context "with wrong type" do
43
+ it "raises ArgumentError" do
44
+ lambda { subject.add(:catty_smith, "123456") }.should raise_error ArgumentError
45
+ end
46
+ end
47
+
48
+ context "with correct type" do
49
+ it "does not raise ArgumentError" do
50
+ subject.add("Catty Smith", "123456")
51
+ lambda { subject.add("Catty Smith", "123456") }.should_not raise_error ArgumentError
52
+ lambda { subject.add("Catty Smith", 123456) }.should_not raise_error ArgumentError
53
+ end
54
+ end
55
+
56
+ context "without argument validation" do
57
+ it "does not raise ArgumentError" do
58
+ lambda { subject.size }.should_not raise_error ArgumentError
59
+ end
60
+ end
61
+ end
62
+
63
+ context "class method" do
64
+ context "with wrong type" do
65
+ it "raises ArgumentError" do
66
+ lambda { subject.class.find_for_owner(:peter_smith) }.should raise_error ArgumentError
67
+ end
68
+ end
69
+
70
+ context "with correct type" do
71
+ it "does not raise ArgumentError" do
72
+ lambda { subject.class.find_for_owner("Peter Smith") }.should_not raise_error ArgumentError
73
+ end
74
+ end
75
+
76
+ context "without argument validation" do
77
+ it "does not raise ArgumentError" do
78
+ lambda { subject.class.phone_books }.should_not raise_error ArgumentError
79
+ end
80
+ end
81
+ end
82
+ end
83
+
84
+ context "for description of optional parameter" do
85
+ subject do
86
+ Class.new do
87
+ include ActiveDoc
88
+ takes :conjunction, String
89
+ def join(conjunction = ","); end
90
+ end.new
91
+ end
92
+
93
+ it "validates only when argument is given" do
94
+ lambda{ subject.join }.should_not raise_error ArgumentError
95
+ lambda{ subject.join(";") }.should_not raise_error ArgumentError
96
+ lambda{ subject.join(2) }.should raise_error ArgumentError
97
+ end
98
+ end
99
+
100
+ context "with nested description of hash" do
101
+ let :subject_class do
102
+ Class.new do
103
+ include ActiveDoc
104
+ takes :options, Hash do
105
+ takes :conjunction, String
106
+ end
107
+ def join(options); end
108
+ end
109
+ end
110
+
111
+ context "when described key is not specified" do
112
+ subject { lambda { subject_class.new.join({})} }
113
+
114
+ it { should_not raise_error ArgumentError }
115
+ end
116
+
117
+ context "when described key has wrong value" do
118
+ subject { lambda { subject_class.new.join(:conjunction => 2)} }
119
+
120
+ it { should raise_error ArgumentError }
121
+ end
122
+
123
+ context "when described key has valid value" do
124
+ subject { lambda { subject_class.new.join(:conjunction => ",")} }
125
+
126
+ it { should_not raise_error ArgumentError }
127
+ end
128
+
129
+ context "when undescribed key is given" do
130
+ subject { lambda { subject_class.new.join(:last_conjunction => "and")} }
131
+
132
+ it { should raise_error ArgumentError }
133
+ end
134
+
135
+ describe "Rdoc comment" do
136
+ subject { ActiveDoc::RdocGenerator.for_method(subject_class, :join) }
137
+
138
+ it { should == <<RDOC }
139
+ # ==== Attributes:
140
+ # * +options+ :: (Hash):
141
+ # * +:conjunction+ :: (String)
142
+ RDOC
143
+ end
144
+ end
145
+
146
+ describe "none expectation specified" do
147
+ let :subject_class do
148
+ Class.new do
149
+ include ActiveDoc
150
+ takes :conjunction, :desc => "String between items when joining"
151
+ def join(conjunction); end
152
+ end
153
+ end
154
+
155
+ describe "Validation" do
156
+ subject { lambda { subject_class.new.join(";") } }
157
+
158
+ it { should_not raise_error ArgumentError }
159
+ end
160
+
161
+ describe "Rdoc comment" do
162
+ subject { ActiveDoc::RdocGenerator.for_method(subject_class, :join)}
163
+
164
+ it { should == <<RDOC }
165
+ # ==== Attributes:
166
+ # * +conjunction+ :: String between items when joining
167
+ RDOC
168
+ end
169
+ end
170
+
171
+ describe "type argument expectation" do
172
+ let :subject_class do
173
+ Class.new do
174
+ include ActiveDoc
175
+ takes :conjunction, String
176
+ def join(conjunction); end
177
+ end
178
+ end
179
+
180
+ describe "Validation" do
181
+ context "for valid value" do
182
+ subject { lambda { subject_class.new.join(";") } }
183
+
184
+ it { should_not raise_error ArgumentError }
185
+ end
186
+
187
+ context "for invalid value" do
188
+ subject { lambda { subject_class.new.join(1) } }
189
+
190
+ it { should raise_error ArgumentError }
191
+ end
192
+ end
193
+
194
+ describe "Rdoc comment" do
195
+ subject { ActiveDoc::RdocGenerator.for_method(subject_class, :join)}
196
+
197
+ it { should == <<RDOC }
198
+ # ==== Attributes:
199
+ # * +conjunction+ :: (String)
200
+ RDOC
201
+ end
202
+ end
203
+
204
+ describe "regexp argument expectation" do
205
+ let :subject_class do
206
+ Class.new do
207
+ include ActiveDoc
208
+ takes :conjunction, /^(and|or)$/
209
+ def join(conjunction) ; end
210
+ end
211
+ end
212
+
213
+ describe "Validation" do
214
+ context "for valid value" do
215
+ subject { lambda { subject_class.new.join("and") } }
216
+
217
+ it { should_not raise_error ArgumentError }
218
+ end
219
+
220
+ context "for invalid value" do
221
+ subject { lambda { subject_class.new.join("xor") } }
222
+
223
+ it { should raise_error ArgumentError }
224
+ end
225
+ end
226
+
227
+ describe "Rdoc comment" do
228
+ subject { ActiveDoc::RdocGenerator.for_method(subject_class, :join) }
229
+
230
+ it { should == <<RDOC }
231
+ # ==== Attributes:
232
+ # * +conjunction+ :: (/^(and|or)$/)
233
+ RDOC
234
+ end
235
+ end
236
+
237
+ describe "array argument expectation" do
238
+ let :subject_class do
239
+ Class.new do
240
+ include ActiveDoc
241
+ takes :conjunction, %w{and or}
242
+ def join(conjunction); end
243
+ end
244
+ end
245
+
246
+ describe "Validation" do
247
+ context "for valid value" do
248
+ subject { lambda { subject_class.new.join("and") } }
249
+
250
+ it { should_not raise_error ArgumentError }
251
+ end
252
+
253
+ context "for invalid value" do
254
+ subject { lambda { subject_class.new.join("xor") } }
255
+
256
+ it { should raise_error ArgumentError }
257
+ end
258
+ end
259
+
260
+ describe "Rdoc comment" do
261
+ subject { ActiveDoc::RdocGenerator.for_method(subject_class, :join) }
262
+
263
+ it { should == <<RDOC }
264
+ # ==== Attributes:
265
+ # * +conjunction+ :: (["and", "or"])
266
+ RDOC
267
+ end
268
+ end
269
+
270
+
271
+ describe "complex condition argument expectation" do
272
+ let :subject_class do
273
+ Class.new do
274
+ include ActiveDoc
275
+ takes(:number){|args| args[:number] != 0 }
276
+ def divide(number) ; end
277
+ end
278
+ end
279
+
280
+ describe "Validation" do
281
+ context "for valid value" do
282
+ subject { lambda { subject_class.new.divide(1) } }
283
+
284
+ it { should_not raise_error ArgumentError }
285
+ end
286
+
287
+ context "for invalid value" do
288
+ subject { lambda { subject_class.new.divide(0) } }
289
+
290
+ it { should raise_error ArgumentError }
291
+ end
292
+ end
293
+
294
+ describe "Rdoc comment" do
295
+ subject { ActiveDoc::RdocGenerator.for_method(subject_class, :divide) }
296
+
297
+ it { should == <<RDOC }
298
+ # ==== Attributes:
299
+ # * +number+ :: (Complex Condition)
300
+ RDOC
301
+ end
302
+ end
303
+
304
+ describe "duck typing argument expectation" do
305
+ let :subject_class do
306
+ Class.new do
307
+ include ActiveDoc
308
+ takes :collection, :duck => :each
309
+ takes :count, :duck => [:succ, :pred]
310
+ def sum(collection, count); end
311
+ end
312
+ end
313
+
314
+ describe "Validation" do
315
+ context "for valid value" do
316
+ subject { lambda { subject_class.new.sum([1,2,3], 2) } }
317
+
318
+ it { should_not raise_error ArgumentError }
319
+ end
320
+
321
+ context "for invalid value" do
322
+ subject { lambda { subject_class.new.sum(:s1_2_3, 2) } }
323
+
324
+ it { should raise_error ArgumentError }
325
+ end
326
+ end
327
+
328
+ describe "Rdoc comment" do
329
+ subject { ActiveDoc::RdocGenerator.for_method(subject_class, :sum) }
330
+
331
+ it { should == <<RDOC }
332
+ # ==== Attributes:
333
+ # * +collection+ :: (respond to :each)
334
+ # * +count+ :: (respond to [:succ, :pred])
335
+ RDOC
336
+ end
337
+ end
338
+
339
+
340
+ end
341
+
@@ -0,0 +1,85 @@
1
+ require 'spec_helper'
2
+
3
+ describe ActiveDoc::RdocGenerator do
4
+ let(:documented_class_path) { File.expand_path("../../support/documented_class.rb", __FILE__) }
5
+ before(:each) do
6
+ @original_documented_class = File.read(documented_class_path)
7
+ load documented_class_path
8
+ end
9
+
10
+ after(:each) do
11
+ File.open(documented_class_path, "w") { |f| f << @original_documented_class }
12
+ end
13
+
14
+ it "writes generated rdoc to file" do
15
+ ActiveDoc::RdocGenerator.write_rdoc(documented_class_path)
16
+ documented_class = File.read(documented_class_path)
17
+ documented_class.should == <<RUBY.chomp
18
+ class PhoneNumber
19
+ include ActiveDoc
20
+
21
+ takes :contact_name, String, :desc => "Name of person"
22
+ takes :number, /^\\d+$/, :desc => "Phone number"
23
+ takes :options, Hash do
24
+ takes :category, String, :desc => "Category of this contact"
25
+ end
26
+ # ==== Attributes:
27
+ # * +contact_name+ :: (String) :: Name of person
28
+ # * +number+ :: (/^\\\\d+$/) :: Phone number
29
+ # * +options+ :: (Hash):
30
+ # * +:category+ :: (String) :: Category of this contact
31
+ def initialize(contact_name, number, options = {})
32
+
33
+ end
34
+ end
35
+ class PhoneBook
36
+ include ActiveDoc
37
+ attr_accessor :owner
38
+
39
+ def initialize(owner)
40
+ @numbers = []
41
+ PhoneBook.register(self)
42
+ end
43
+
44
+ takes :contact_name, :ref => "PhoneNumber#initialize"
45
+ takes :number, :ref => "PhoneNumber#initialize"
46
+ takes :options, :ref => "PhoneNumber#initialize"
47
+ # ==== Attributes:
48
+ # * +contact_name+ :: (String) :: Name of person
49
+ # * +number+ :: (/^\\\\d+$/) :: Phone number
50
+ # * +options+ :: (Hash):
51
+ # * +:category+ :: (String) :: Category of this contact
52
+ def add(contact_name, number, options = {})
53
+ @numbers << PhoneNumber.new(contact_name, number, options)
54
+ end
55
+
56
+ takes :owner, String
57
+ # ==== Attributes:
58
+ # * +owner+ :: (String)
59
+ def self.find_for_owner(owner)
60
+ @phone_books && @phone_books[owner]
61
+ end
62
+
63
+ class << self
64
+ takes :phone_book, PhoneBook
65
+ # ==== Attributes:
66
+ # * +phone_book+ :: (PhoneBook)
67
+ def register(phone_book)
68
+ @phone_books ||= {}
69
+ @phone_books[phone_book.owner] = phone_book
70
+ end
71
+ end
72
+
73
+ def self.phone_books
74
+ return @phone_books.values
75
+ end
76
+
77
+ def size
78
+ return @numbers.size
79
+ end
80
+ end
81
+ RUBY
82
+ end
83
+
84
+ end
85
+