active_doc 0.1.0

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