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.
- data/.gitignore +2 -0
- data/Gemfile +6 -0
- data/History.txt +38 -0
- data/LICENSE +22 -0
- data/README.rdoc +202 -0
- data/active_doc.gemspec +32 -0
- data/lib/active_doc.rb +83 -0
- data/lib/active_doc/described_method.rb +38 -0
- data/lib/active_doc/descriptions.rb +1 -0
- data/lib/active_doc/descriptions/method_argument_description.rb +426 -0
- data/lib/active_doc/rake/task.rb +48 -0
- data/lib/active_doc/rdoc_generator.rb +21 -0
- data/spec/active_doc/method_argument_description_spec.rb +341 -0
- data/spec/active_doc/rdoc_generator_spec.rb +85 -0
- data/spec/spec_helper.rb +1 -0
- data/spec/support/documented_class.rb +53 -0
- metadata +116 -0
@@ -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
|
+
|