dionysus 2.1.0 → 2.2.0.0.pre1

Sign up to get free protection for your applications and to get access to all the features.
data/CONTRIBUTORS.md ADDED
@@ -0,0 +1,11 @@
1
+ # Contributors
2
+
3
+ **Author**: Travis D. Warlick, Jr.
4
+
5
+ * http://tekwiz.github.com/
6
+ * http://github.com/tekwiz
7
+
8
+ MaxMedia
9
+
10
+ * http://www.maxmedia.com
11
+ * http://github.com/maxmedia
data/Gemfile CHANGED
@@ -14,6 +14,7 @@ group :test do
14
14
  gem "shoulda-matchers", "~> 1.2.0"
15
15
  gem "mocha", "~> 0.11.4"
16
16
  gem "simplecov", "~> 0.6.4", :require => false
17
+ gem "faker", "~> 1.0.1"
17
18
  end
18
19
 
19
20
  # Specify core dependencies in core.gemspec
data/LICENSE CHANGED
@@ -1,202 +1,20 @@
1
1
  # -*- md:plaintext -*-
2
- Apache License
3
- Version 2.0, January 2004
4
- http://www.apache.org/licenses/
5
-
6
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7
-
8
- 1. Definitions.
9
-
10
- "License" shall mean the terms and conditions for use, reproduction,
11
- and distribution as defined by Sections 1 through 9 of this document.
12
-
13
- "Licensor" shall mean the copyright owner or entity authorized by
14
- the copyright owner that is granting the License.
15
-
16
- "Legal Entity" shall mean the union of the acting entity and all
17
- other entities that control, are controlled by, or are under common
18
- control with that entity. For the purposes of this definition,
19
- "control" means (i) the power, direct or indirect, to cause the
20
- direction or management of such entity, whether by contract or
21
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
22
- outstanding shares, or (iii) beneficial ownership of such entity.
23
-
24
- "You" (or "Your") shall mean an individual or Legal Entity
25
- exercising permissions granted by this License.
26
-
27
- "Source" form shall mean the preferred form for making modifications,
28
- including but not limited to software source code, documentation
29
- source, and configuration files.
30
-
31
- "Object" form shall mean any form resulting from mechanical
32
- transformation or translation of a Source form, including but
33
- not limited to compiled object code, generated documentation,
34
- and conversions to other media types.
35
-
36
- "Work" shall mean the work of authorship, whether in Source or
37
- Object form, made available under the License, as indicated by a
38
- copyright notice that is included in or attached to the work
39
- (an example is provided in the Appendix below).
40
-
41
- "Derivative Works" shall mean any work, whether in Source or Object
42
- form, that is based on (or derived from) the Work and for which the
43
- editorial revisions, annotations, elaborations, or other modifications
44
- represent, as a whole, an original work of authorship. For the purposes
45
- of this License, Derivative Works shall not include works that remain
46
- separable from, or merely link (or bind by name) to the interfaces of,
47
- the Work and Derivative Works thereof.
48
-
49
- "Contribution" shall mean any work of authorship, including
50
- the original version of the Work and any modifications or additions
51
- to that Work or Derivative Works thereof, that is intentionally
52
- submitted to Licensor for inclusion in the Work by the copyright owner
53
- or by an individual or Legal Entity authorized to submit on behalf of
54
- the copyright owner. For the purposes of this definition, "submitted"
55
- means any form of electronic, verbal, or written communication sent
56
- to the Licensor or its representatives, including but not limited to
57
- communication on electronic mailing lists, source code control systems,
58
- and issue tracking systems that are managed by, or on behalf of, the
59
- Licensor for the purpose of discussing and improving the Work, but
60
- excluding communication that is conspicuously marked or otherwise
61
- designated in writing by the copyright owner as "Not a Contribution."
62
-
63
- "Contributor" shall mean Licensor and any individual or Legal Entity
64
- on behalf of whom a Contribution has been received by Licensor and
65
- subsequently incorporated within the Work.
66
-
67
- 2. Grant of Copyright License. Subject to the terms and conditions of
68
- this License, each Contributor hereby grants to You a perpetual,
69
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70
- copyright license to reproduce, prepare Derivative Works of,
71
- publicly display, publicly perform, sublicense, and distribute the
72
- Work and such Derivative Works in Source or Object form.
73
-
74
- 3. Grant of Patent License. Subject to the terms and conditions of
75
- this License, each Contributor hereby grants to You a perpetual,
76
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77
- (except as stated in this section) patent license to make, have made,
78
- use, offer to sell, sell, import, and otherwise transfer the Work,
79
- where such license applies only to those patent claims licensable
80
- by such Contributor that are necessarily infringed by their
81
- Contribution(s) alone or by combination of their Contribution(s)
82
- with the Work to which such Contribution(s) was submitted. If You
83
- institute patent litigation against any entity (including a
84
- cross-claim or counterclaim in a lawsuit) alleging that the Work
85
- or a Contribution incorporated within the Work constitutes direct
86
- or contributory patent infringement, then any patent licenses
87
- granted to You under this License for that Work shall terminate
88
- as of the date such litigation is filed.
89
-
90
- 4. Redistribution. You may reproduce and distribute copies of the
91
- Work or Derivative Works thereof in any medium, with or without
92
- modifications, and in Source or Object form, provided that You
93
- meet the following conditions:
94
-
95
- (a) You must give any other recipients of the Work or
96
- Derivative Works a copy of this License; and
97
-
98
- (b) You must cause any modified files to carry prominent notices
99
- stating that You changed the files; and
100
-
101
- (c) You must retain, in the Source form of any Derivative Works
102
- that You distribute, all copyright, patent, trademark, and
103
- attribution notices from the Source form of the Work,
104
- excluding those notices that do not pertain to any part of
105
- the Derivative Works; and
106
-
107
- (d) If the Work includes a "NOTICE" text file as part of its
108
- distribution, then any Derivative Works that You distribute must
109
- include a readable copy of the attribution notices contained
110
- within such NOTICE file, excluding those notices that do not
111
- pertain to any part of the Derivative Works, in at least one
112
- of the following places: within a NOTICE text file distributed
113
- as part of the Derivative Works; within the Source form or
114
- documentation, if provided along with the Derivative Works; or,
115
- within a display generated by the Derivative Works, if and
116
- wherever such third-party notices normally appear. The contents
117
- of the NOTICE file are for informational purposes only and
118
- do not modify the License. You may add Your own attribution
119
- notices within Derivative Works that You distribute, alongside
120
- or as an addendum to the NOTICE text from the Work, provided
121
- that such additional attribution notices cannot be construed
122
- as modifying the License.
123
-
124
- You may add Your own copyright statement to Your modifications and
125
- may provide additional or different license terms and conditions
126
- for use, reproduction, or distribution of Your modifications, or
127
- for any such Derivative Works as a whole, provided Your use,
128
- reproduction, and distribution of the Work otherwise complies with
129
- the conditions stated in this License.
130
-
131
- 5. Submission of Contributions. Unless You explicitly state otherwise,
132
- any Contribution intentionally submitted for inclusion in the Work
133
- by You to the Licensor shall be under the terms and conditions of
134
- this License, without any additional terms or conditions.
135
- Notwithstanding the above, nothing herein shall supersede or modify
136
- the terms of any separate license agreement you may have executed
137
- with Licensor regarding such Contributions.
138
-
139
- 6. Trademarks. This License does not grant permission to use the trade
140
- names, trademarks, service marks, or product names of the Licensor,
141
- except as required for reasonable and customary use in describing the
142
- origin of the Work and reproducing the content of the NOTICE file.
143
-
144
- 7. Disclaimer of Warranty. Unless required by applicable law or
145
- agreed to in writing, Licensor provides the Work (and each
146
- Contributor provides its Contributions) on an "AS IS" BASIS,
147
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148
- implied, including, without limitation, any warranties or conditions
149
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150
- PARTICULAR PURPOSE. You are solely responsible for determining the
151
- appropriateness of using or redistributing the Work and assume any
152
- risks associated with Your exercise of permissions under this License.
153
-
154
- 8. Limitation of Liability. In no event and under no legal theory,
155
- whether in tort (including negligence), contract, or otherwise,
156
- unless required by applicable law (such as deliberate and grossly
157
- negligent acts) or agreed to in writing, shall any Contributor be
158
- liable to You for damages, including any direct, indirect, special,
159
- incidental, or consequential damages of any character arising as a
160
- result of this License or out of the use or inability to use the
161
- Work (including but not limited to damages for loss of goodwill,
162
- work stoppage, computer failure or malfunction, or any and all
163
- other commercial damages or losses), even if such Contributor
164
- has been advised of the possibility of such damages.
165
-
166
- 9. Accepting Warranty or Additional Liability. While redistributing
167
- the Work or Derivative Works thereof, You may choose to offer,
168
- and charge a fee for, acceptance of support, warranty, indemnity,
169
- or other liability obligations and/or rights consistent with this
170
- License. However, in accepting such obligations, You may act only
171
- on Your own behalf and on Your sole responsibility, not on behalf
172
- of any other Contributor, and only if You agree to indemnify,
173
- defend, and hold each Contributor harmless for any liability
174
- incurred by, or claims asserted against, such Contributor by reason
175
- of your accepting any such warranty or additional liability.
176
-
177
- END OF TERMS AND CONDITIONS
178
-
179
- APPENDIX: How to apply the Apache License to your work.
180
-
181
- To apply the Apache License to your work, attach the following
182
- boilerplate notice, with the fields enclosed by brackets "[]"
183
- replaced with your own identifying information. (Don't include
184
- the brackets!) The text should be enclosed in the appropriate
185
- comment syntax for the file format. We also recommend that a
186
- file or class name and description of purpose be included on the
187
- same "printed page" as the copyright notice for easier
188
- identification within third-party archives.
189
-
190
- Copyright [yyyy] [name of copyright owner]
191
-
192
- Licensed under the Apache License, Version 2.0 (the "License");
193
- you may not use this file except in compliance with the License.
194
- You may obtain a copy of the License at
195
-
196
- http://www.apache.org/licenses/LICENSE-2.0
197
-
198
- Unless required by applicable law or agreed to in writing, software
199
- distributed under the License is distributed on an "AS IS" BASIS,
200
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
201
- See the License for the specific language governing permissions and
202
- limitations under the License.
2
+ Copyright (c) 2012 Travis Warlick
3
+
4
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
5
+ this software and associated documentation files (the "Software"), to deal in
6
+ the Software without restriction, including without limitation the rights to
7
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
8
+ of the Software, and to permit persons to whom the Software is furnished to do
9
+ so, subject to the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be included in all
12
+ copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20
+ SOFTWARE.
data/README.md CHANGED
@@ -45,20 +45,9 @@ since parts are bound to conflict with something you're using at some point.
45
45
 
46
46
  ## Contributing
47
47
 
48
- This project is intended to be a **very** eclectic mix of helpful tools, so please feel free to send pull requests. That said, make **absolutely sure** your modifications are well tested. The hodge-podge nature of this project may make it prone to issues, so no code will be pulled-in that is not __fully_tested__.
48
+ * see {file:docs/STANDARDS.md Standards for Contributing}
49
+ * see {file:docs/CONTRIBUTORS.md Contributors}
49
50
 
50
51
  -----------------------------
51
52
 
52
- Copyright 2012 Travis D. Warlick, Jr.
53
-
54
- Licensed under the Apache License, Version 2.0 (the "License");
55
- you may not use this file except in compliance with the License.
56
- You may obtain a copy of the License at
57
-
58
- http://www.apache.org/licenses/LICENSE-2.0
59
-
60
- Unless required by applicable law or agreed to in writing, software
61
- distributed under the License is distributed on an "AS IS" BASIS,
62
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
63
- See the License for the specific language governing permissions and
64
- limitations under the License.
53
+ <<< LICENSE
data/docs/CHANGELOG.md CHANGED
@@ -1,5 +1,28 @@
1
1
  # Dionysus Changelog
2
2
 
3
+ ## 2.2.0.0
4
+
5
+ *ACTIVE DEVELOPMENT*
6
+
7
+ ### 2.2.0.0.pre1
8
+
9
+ *2012 September 4*
10
+
11
+ * Changed licensing to the more simple {file:LICENSE MIT License}
12
+ `*` see ["MIT License" on Wikipedia](http://en.wikipedia.org/wiki/MIT_License)
13
+ * Added {Array}#assert_types
14
+ * Added {Dionysus::Decorator} and {Dionysus::Decoratable}
15
+ * Added {Dionysus::ForwardableToClass}
16
+ * Added {Dionysus::ForwardableWithReturn}
17
+ * Added `class_attr_*_typed` methods for {Module}
18
+ * Added {Module}#class_dsl_attr_accessor
19
+ * Fixed file preprocessing in {Dionysus::Redcarpet::Includes}
20
+ * Fixed {Dionysus::TravisCI::GemfileGenerator} with runtime dependencies defined in the Gemfile
21
+ * Added {file:VERSIONING.md} document and changed versioning scheme
22
+ * Added {file:STANDARDS.md} document
23
+ * Added {file:CONTRIBUTORS.md} document
24
+ * Moved to git-flow development
25
+
3
26
  ## 2.1.0
4
27
 
5
28
  *2012 June 28*
@@ -7,8 +30,8 @@
7
30
  * Fixed alias method chaining in {Dionysus::Redcarpet::Includes} extension
8
31
  * Added {Dionysus::Redcarpet::Plaintext} extension for marking files that should be rendered in `<pre>` tags
9
32
  * Refactored out redcarpet regex constants to {Dionysus::Redcarpet} module
10
- * Added this Changelog
11
- * Added the Roadmap
33
+ * Added this {file:docs/CHANGELOG.md}
34
+ * Added the {file:docs/ROADMAP.md}
12
35
  * Setup documentation site http://tekwiz.github.com/dionysus
13
36
 
14
37
  ## 2.0.0 *Major Re-release*
data/docs/STANDARDS.md ADDED
@@ -0,0 +1,45 @@
1
+ # Standards for Contributing
2
+
3
+ This project is intended to be a **very** eclectic mix of helpful tools, so
4
+ please feel free to send pull requests. That said, make **absolutely sure**
5
+ your modifications are well tested. The hodge-podge nature of this project may
6
+ make it prone to issues, so no code will be pulled-in that is not
7
+ __fully_tested__.
8
+
9
+ ## Runtime Dependencies
10
+
11
+ The only runtime dependency allowed for Dionysus is ActiveSupport; however,
12
+ specific modules may require their own dependencies. These additional
13
+ dependencies shall be defined in the Gemfile in the `development` and `test`
14
+ groups and their version requirements must be as loose as possible.
15
+
16
+ ## Testing
17
+
18
+ Test coverage must be 100% at C0, and best practices for testing edge and
19
+ corner cases must be followed.
20
+
21
+ ## Documentation
22
+
23
+ All public and protected methods must be fully documented with YARD, and
24
+ classes and modules must be properly documented as well. Modules and classes
25
+ that have dependencies should document so.
26
+
27
+ ## Copyright
28
+
29
+ Contributors may include their own copyright notice in their source files;
30
+ however, all contributions must be licensed under the MIT license or similar
31
+ X11/BSD license
32
+ (see ["MIT License" on Wikipedia](http://en.wikipedia.org/wiki/MIT_License)).
33
+ Additionally, contributions which include a copyright license must include a
34
+ clause or clauses for disclaimer of warranty and limitation of liability.
35
+ Finally, contributions with third-party code must respect the copyright and
36
+ license of that code.
37
+
38
+ Contributions with copy-left restrictions or patented technology will not be
39
+ accepted. This includes contributions with licenses that include patent
40
+ license verbiage, such as the
41
+ [Apache 2.0 License](http://www.apache.org/licenses/LICENSE-2.0).
42
+
43
+ Note that these restrictions do not restrict referencing third-party libraries
44
+ or applications with proprietary licensing since the onus of such licenses is
45
+ on the end-user.
@@ -0,0 +1,40 @@
1
+ # Versioning
2
+
3
+ Dionysus uses system of semantic versioning using 4 numbers instead of the usual 3. This is because Dionysus is extremely diverse in its functionality and components can be, and are, added often without affecting any other component.
4
+
5
+ The TLDR of the versioning scheme is:
6
+
7
+ * Micro and patch releases will not break backwards compatibility.
8
+ * Minor releases *might* break backwards compatibility.
9
+ * Major releases **will** break backwards compatibility.
10
+
11
+ ## Components
12
+
13
+ Major.Minor.Micro.Patch[.Prerelease]
14
+
15
+ ### Major
16
+
17
+ An upgrade of the major component indicates a **major** upgrade of dionysus that will break backwards compatibility. This might a major restructuring or a major dependency change.
18
+
19
+ ### Minor
20
+
21
+ An upgrade of the minor component indicates a significant change that might break backwards compatibility, cause dependency conflicts, or remove support for a dependency.
22
+
23
+ ### Micro
24
+
25
+ An upgrade of the micro component indicates a significant change that will not break backwards compatibility or have dependency changes. This will be a significant feature addition that is independent and isolated.
26
+
27
+ ### Patch
28
+
29
+ An upgrade of the patch component indicates a simple change that will not break backwards compatibility or have dependency changes. This will include bug fixes and simple feature additions or enhancements.
30
+
31
+ ### Prerelease
32
+
33
+ The Prerelease component indicates a version change that is not considered "production ready" but is considered safe enough for official release; its purpose is for testing and to allow developers to write code against the future release while testing is still ongoing`*`. This may include completely or partially untested code or code that needs additional platform or dependency testing.
34
+
35
+ `*` See the {file:LICENSE} regarding disclaimer of warranty and limitation of liability.
36
+
37
+ ## Resources:
38
+
39
+ * [Semver.org](http://semver.org/)
40
+ * ["Software versioning" on Wikipedia](http://en.wikipedia.org/wiki/Software_versioning)
@@ -0,0 +1,22 @@
1
+ class Array
2
+ # Assert that the elements in the Array are of the given types
3
+ #
4
+ # @param types [*Class] list of Classes to match against the elements
5
+ # @return [true] if all elements are of the proper type
6
+ # @return [false] otherwise
7
+ # @raise ArgumentError if the number of arguments does not match the length of the Array
8
+ # @raise ArgumentError if an element does not match the require type in the arguments
9
+ def assert_types(*types)
10
+ if types.length != self.length
11
+ raise ArgumentError, "Number of arguments must match length of Array"
12
+ end
13
+
14
+ each_index do |i|
15
+ unless self[i].is_a?(types[i])
16
+ raise ArgumentError, "Value at index %s expected to be a %s"%[i, types[i]]
17
+ end
18
+ end
19
+
20
+ true
21
+ end
22
+ end
@@ -0,0 +1,138 @@
1
+ # Copyright (c) 2012 MaxMedia and Travis Warlick
2
+ # Licensed under the MIT License (see LICENSE)
3
+
4
+ require 'active_support/concern'
5
+ require 'active_support/callbacks'
6
+ require 'dionysus/array/assert_types'
7
+
8
+ module Dionysus
9
+ module Decorator
10
+ def extend_object(base)
11
+ if base.class == Class or base.class == Module
12
+ super
13
+ else
14
+ _decorations.setup(base)
15
+ if const_defined?("Methods")
16
+ base.send :extend, const_get("Methods")
17
+ end
18
+ end
19
+ end
20
+
21
+ def before(*args, &block)
22
+ name, options, block = callback_args(*(args + [block]))
23
+ _decorations.add(name, :before, options || {}, block)
24
+ end
25
+
26
+ def after(*args, &block)
27
+ name, options, block = callback_args(*(args + [block]))
28
+ _decorations.add(name, :after, options || {}, block)
29
+ end
30
+
31
+ # TODO implement around callback. Currently breaks with: no block given (yield) (LocalJumpError)
32
+ # def around(*args, &block)
33
+ # name, options, block = callback_args(*(args + [block]))
34
+ # _decorations.add(name, :around, options || {}, block)
35
+ # end
36
+
37
+ def decorate(&block)
38
+ _decorations.add block
39
+ end
40
+
41
+ private
42
+
43
+ def callback_args(*args)
44
+ args = args.compact
45
+
46
+ name = args.shift
47
+
48
+ block = args.detect {|obj| obj.is_a?(Proc)}
49
+ args.delete(block) if block
50
+
51
+ options = args.detect {|obj| obj.is_a?(Hash)}
52
+ args.delete(options) if options
53
+
54
+ if args.length > 0
55
+ raise ArgumentError, "Too many arguments"
56
+ end
57
+
58
+ return name, options, block
59
+ end
60
+
61
+ def _decorations
62
+ @_decorations ||= Decorations.new(self)
63
+ end
64
+
65
+ class Decorations
66
+ def initialize(mod)
67
+ @module = mod
68
+ @callbacks = {}
69
+ @blocks = []
70
+ end
71
+
72
+ def add(*args)
73
+ if args.length == 1 and args[0].is_a?(Proc)
74
+ @blocks << args.first
75
+ else
76
+ name = args.shift.to_sym
77
+ args.assert_types(Symbol, Hash, Proc)
78
+ (@callbacks[name] ||= []).tap do |array|
79
+ array << Callback.new(*args)
80
+ end
81
+ end
82
+ end
83
+
84
+ def setup(obj)
85
+ setup_callbacks(obj)
86
+ obj.extend build_decorator_module
87
+ @blocks.each { |b| obj.instance_eval(&b) }
88
+ end
89
+
90
+ private
91
+
92
+ def setup_callbacks(obj)
93
+ obj.class.define_callbacks *@callbacks.keys
94
+ @callbacks.each do |name, callbacks|
95
+ callbacks.each { |cb| cb.setup(obj, name) }
96
+ end
97
+ end
98
+
99
+ def build_decorator_module
100
+ Module.new.tap do |result|
101
+ @callbacks.keys.each do |name|
102
+ result.module_eval(<<-EOS, __FILE__, __LINE__ + 1)
103
+ def #{name}(*args, &block)
104
+ run_callbacks(#{name.to_sym.inspect}) do
105
+ super(*args, &block)
106
+ end
107
+ end
108
+ EOS
109
+ end
110
+ end
111
+ end
112
+
113
+ class Callback < Struct.new(:type, :options, :block)
114
+ def setup(obj, name)
115
+ obj.class.set_callback(name, type, options, &block)
116
+ end
117
+ end
118
+ end
119
+ end
120
+
121
+ module Decoratable
122
+ extend ActiveSupport::Concern
123
+ include ActiveSupport::Callbacks
124
+
125
+ def decorate_with(mod)
126
+ # self is Object decendant instance (which includes Decoratable)
127
+ # TODO verify mod extends the Decorator module
128
+ if mod.is_a?(Class)
129
+ mod.extend_object(self)
130
+ elsif mod.is_a?(Module)
131
+ self.extend(mod)
132
+ else
133
+ raise ArgumentError, "Wrong type %p. Expected extension of Dionysus::Decorator"%[mod.class]
134
+ end
135
+ end
136
+ alias_method :with, :decorate_with
137
+ end
138
+ end
@@ -0,0 +1,22 @@
1
+ # Copyright (c) 2012 MaxMedia and Travis Warlick
2
+ # Licensed under the MIT License (see LICENSE)
3
+
4
+ module Dionysus
5
+ module ForwardableToClass
6
+ include Forwardable
7
+
8
+ def def_instance_delegator_to_class(method, ali=method)
9
+ def_instance_delegator "self.class", method, ali
10
+ end
11
+ alias_method :def_delegator_to_class, :def_instance_delegator_to_class
12
+
13
+ def def_instance_delegators_to_class(*methods)
14
+ for method in methods
15
+ def_instance_delegator_to_class(method)
16
+ end
17
+ end
18
+ alias_method :def_delegators_to_class, :def_instance_delegators_to_class
19
+ alias_method :instance_delegate_to_class, :def_instance_delegators_to_class
20
+ alias_method :delegate_to_class, :def_instance_delegators_to_class
21
+ end
22
+ end
@@ -0,0 +1,42 @@
1
+ # Copyright (c) 2012 MaxMedia and Travis Warlick
2
+ # Licensed under the MIT License (see LICENSE)
3
+
4
+ module Dionysus
5
+ module ForwardableWithReturn
6
+ include Forwardable
7
+
8
+ def def_instance_delegator_with_return(accessor, method, return_method=:self, ali=method)
9
+ def_instance_delegator(accessor, method, :"__delegated_#{ali}")
10
+ private :"__delegated_#{ali}"
11
+ line_no, code = __LINE__, <<-EOC
12
+ def #{ali}(*args, &block)
13
+ __send__(:"__delegated_#{ali}", *args, &block)
14
+ #{return_method}
15
+ end
16
+ EOC
17
+ begin
18
+ module_eval(code, __FILE__, line_no)
19
+ rescue
20
+ instance_eval(code, __FILE__, line_no)
21
+ end
22
+ end
23
+ alias_method :def_delegator_with_return, :def_instance_delegator_with_return
24
+
25
+ def def_instance_delegators_with_return(accessor, return_method, *methods)
26
+ methods.delete("__send__")
27
+ methods.delete("__id__")
28
+ for method in methods
29
+ def_instance_delegator(accessor, method, return_method)
30
+ end
31
+ end
32
+ alias_method :def_delegators_with_return, :def_instance_delegators_with_return
33
+
34
+ def instance_delegate_with_return(return_method, hash={})
35
+ hash.each do |methods, accessor|
36
+ methods = [methods] unless methods.respond_to?(:each)
37
+ def_instance_delegators_with_return(accessor, return_method, *methods)
38
+ end
39
+ end
40
+ alias_method :delegate_with_return, :instance_delegate_with_return
41
+ end
42
+ end
@@ -0,0 +1,64 @@
1
+ # Copyright (c) 2012 MaxMedia and Travis Warlick
2
+ # Licensed under the MIT License (see LICENSE)
3
+
4
+ class Module
5
+ # Defines a singleton-class attribute writer that ensures the value is always converted to the
6
+ # given type by using the method in the options or creating a new instance of the `type` class
7
+ # and passing the value to its initializer.
8
+ #
9
+ # @overload class_attr_writer_typed(type, *names)
10
+ # @param type [Class] class to ensure the value is
11
+ # @param names [*Symbol] names of attributes
12
+ #
13
+ # @overload class_attr_writer_typed(type, *names, opts={})
14
+ # @param type [Class] class to ensure the value is
15
+ # @param names [*Symbol] names of attributes
16
+ # @param opts [Hash] options
17
+ # @option opts [Symbol] :method method name to use to convert the values
18
+ def class_attr_writer_typed(type, *names)
19
+ options = names.extract_options!
20
+
21
+ names.each do |name|
22
+ class_eval <<-EOC, __FILE__, __LINE__+1
23
+ def self.#{name}=(val)
24
+ obj = #{options[:method] ? "val.#{options[:method]}" : "val"}
25
+ @#{name} = (obj.is_a?(#{type}) ? obj : #{type}.new(obj))
26
+ end
27
+ EOC
28
+ end
29
+ end
30
+
31
+ # Defines a singleton-class attribute reader that has ensured the value has been converted to the
32
+ # given type.
33
+ #
34
+ # @param type [Class] class to ensure the value is
35
+ # @param names [*Symbol] names of attributes
36
+ # @return [Object] value will be of type defined in the parameters
37
+ # @raise [TypeError] if the value has been modified and is no longer of the proper type
38
+ def class_attr_reader_typed(type, *names)
39
+ options = names.extract_options!
40
+
41
+ names.each do |name|
42
+ class_eval <<-EOC, __FILE__, __LINE__+1
43
+ def self.#{name}
44
+ unless @#{name}.is_a?(#{type})
45
+ raise TypeError, "Expected #{name} to be a #{type}"
46
+ end
47
+ @#{name}
48
+ end
49
+ EOC
50
+ end
51
+ end
52
+
53
+ # Defines a singleton-class attribute reader and writer that ensures the value is always
54
+ # converted to the given type.
55
+ #
56
+ # @see #class_attr_writer_typed
57
+ # @see #class_attr_reader_typed
58
+ def class_attr_accessor_typed(type, *names)
59
+ options = names.extract_options!
60
+
61
+ class_attr_reader_typed type, *names
62
+ class_attr_writer_typed type, *names
63
+ end
64
+ end
@@ -0,0 +1,29 @@
1
+ # Copyright (c) 2012 MaxMedia and Travis Warlick
2
+ # Licensed under the MIT License (see LICENSE)
3
+
4
+ class Module
5
+ # Defines a DSL attribute accessor (or more than one)
6
+ #
7
+ # @param names [*Symbol, *String] list of accessors to create
8
+ #
9
+ # @example Define an accessor
10
+ # module Foo
11
+ # class_dsl_attr_accessor :foo, :bar
12
+ # ene
13
+ # class Bar
14
+ # include Foo
15
+ # foo "fooey"
16
+ # bar foo+" foobar"
17
+ # end
18
+ # Bar.foo # => "fooey"
19
+ # Bar.bar # => "fooey foobar"
20
+ def class_dsl_attr_accessor(*names)
21
+ names.each do |name|
22
+ class_eval <<-EOC, __FILE__, __LINE__+1
23
+ def self.#{name}(val=nil)
24
+ (val ? self.#{name} = val : @#{name})
25
+ end
26
+ EOC
27
+ end
28
+ end
29
+ end
@@ -1,8 +1,93 @@
1
+ require 'active_support/core_ext/module/aliasing'
2
+ require "active_support/concern"
1
3
  require "redcarpet"
2
4
 
3
5
  module Dionysus
4
6
  module Redcarpet
7
+ extend ActiveSupport::Concern
8
+
9
+ # The Syntax for a file directive (first line of the file):
10
+ #
11
+ # @example Hash Comment
12
+ # # -*- md:DIRECTIVE -*-
13
+ #
14
+ # @example Double Slash Comment
15
+ # // -*- md:DIRECTIVE -*-
5
16
  FILE_DIRECTIVE_REGEXP = /\A(?:#|\/\/)\s*-\*-\s*(md):\s*(\S+)\s*-\*-\s*\n/
17
+
18
+ # The Syntax for an inline directive (at the start of any line, indentation is allowed):
19
+ #
20
+ # @example
21
+ # <<< DIRECTIVE
6
22
  LINE_DIRECTIVE_REGEXP = /\A\s*<<<\s*(\S+)\s*\Z/
23
+
24
+ included do
25
+ if method_defined?(:preprocess)
26
+ alias_method_chain :preprocess, :dionysus
27
+ else
28
+ alias_method :preprocess, :preprocess_with_dionysus
29
+ end
30
+ end
31
+
32
+ # @see ClassMethods#file_preprocessors
33
+ def file_preprocessors() self.class.file_preprocessors; end
34
+
35
+ # @see ClassMethods#line_preprocessors
36
+ def line_preprocessors() self.class.line_preprocessors; end
37
+
38
+ # Alias method chain method for preprocessing a document with file_preprocessors and then
39
+ # line_preprocessors.
40
+ #
41
+ # @param full_document [String] Document to preprocess
42
+ # @return [String] the full document, with preprocessors run on it
43
+ def preprocess_with_dionysus(full_document)
44
+ file_preprocessors.each do |block|
45
+ full_document = block.call(self, full_document)
46
+ end
47
+
48
+ return full_document if line_preprocessors.empty?
49
+
50
+ lines = full_document.split($/)
51
+ line_preprocessors.each do |block|
52
+ lines.each_with_index do |ln, i|
53
+ lines[i] = block.call(self, ln)
54
+ end
55
+ lines.flatten!
56
+ end
57
+
58
+ full_document = lines.join("\n")
59
+
60
+ if respond_to? :preprocess_without_dionysus
61
+ preprocess_without_dionysus(full_document)
62
+ else
63
+ full_document
64
+ end
65
+ end
66
+
67
+ module ClassMethods
68
+ # The list of file preprocessors
69
+ def file_preprocessors() @file_preprocessors ||= []; end
70
+
71
+ # The list of line preprpcessors
72
+ def line_preprocessors() @line_preprocessors ||= []; end
73
+
74
+ # @yield [renderer, document] Execute the provided block as a file preprocessor
75
+ # @yieldparam renderer [Redcarpet::Render::Base] renderer for the file
76
+ # @yieldparam document [String] document to preprocess
77
+ # @yieldreturn [String] preprocessed document
78
+ def preprocess_file(&block)
79
+ file_preprocessors << block
80
+ end
81
+
82
+ # @yield [renderer, line] Execute the provided block as a line preprocessor
83
+ # @yieldparam renderer [Redcarpet::Render::Base] renderer for the file
84
+ # @yieldparam line [String] line to preprocess
85
+ # @yieldreturn [String] preprocessed line
86
+ def preprocess_line(&block)
87
+ line_preprocessors << block
88
+ end
89
+ end
7
90
  end
8
91
  end
92
+
93
+ Redcarpet::Render::HTML.send(:include, Dionysus::Redcarpet)
@@ -1,43 +1,33 @@
1
1
  require "pathname"
2
- require "active_support/concern"
3
- require "active_support/core_ext/object/blank"
4
2
  require "dionysus/redcarpet"
3
+ require "active_support/core_ext/object/blank"
5
4
 
6
5
  module Dionysus
7
6
  module Redcarpet
7
+ # This is an extension to Redcarpet that allows you to include a file, preprocessor.
8
+ #
9
+ # @example README.md
10
+ # = This is my README
11
+ # <<< LICENSE.txt
8
12
  module Includes
9
13
  extend ActiveSupport::Concern
10
14
 
11
15
  included do
12
- if method_defined?(:preprocess)
13
- alias_method_chain :preprocess, :includes
14
- else
15
- alias_method :preprocess, :preprocess_with_includes
16
- end
17
- end
18
-
19
- def preprocess_with_includes(full_document)
20
- lines = full_document.split($/)
21
- lines.each_with_index do |ln, i|
22
- if m = ln.match(LINE_DIRECTIVE_REGEXP)
16
+ preprocess_line do |renderer, line|
17
+ if m = line.match(LINE_DIRECTIVE_REGEXP)
23
18
  path = Pathname.new(m[1])
24
19
  if path.file?
25
20
  newlines = path.readlines
26
21
  newlines.collect! {|ln| ln.chomp}
27
22
  newlines.shift while(newlines.first.blank?)
28
23
  newlines.pop while(newlines.last.blank?)
29
- lines[i] = newlines
24
+ line = newlines.join("\n")
25
+ line = renderer.preprocess(line)
30
26
  else
31
27
  warn "[WARNING] Cannot find path %s to include"%[path.to_s]
32
28
  end
33
29
  end
34
- end
35
- full_document = lines.flatten.join("\n")
36
-
37
- if respond_to? :preprocess_without_includes
38
- preprocess_without_includes(full_document)
39
- else
40
- full_document
30
+ line
41
31
  end
42
32
  end
43
33
  end
@@ -1,29 +1,19 @@
1
- require "active_support/concern"
2
1
  require "dionysus/redcarpet"
3
2
 
4
3
  module Dionysus
5
4
  module Redcarpet
5
+ # This is an extension to Redcarpet that preprocesses a file as simple plaintext, simply
6
+ # wrapping the document in fenced code blocks (i.e. triple-backticks).
6
7
  module Plaintext
7
8
  extend ActiveSupport::Concern
8
9
 
9
10
  included do
10
- if method_defined?(:preprocess)
11
- alias_method_chain :preprocess, :plaintext
12
- else
13
- alias_method :preprocess, :preprocess_with_plaintext
14
- end
15
- end
16
-
17
- def preprocess_with_plaintext(full_document)
18
- if full_document =~ FILE_DIRECTIVE_REGEXP
19
- if $1 == "md" and $2 == "plaintext"
20
- full_document = "```\n#{full_document.gsub(FILE_DIRECTIVE_REGEXP, "")}\n```"
11
+ preprocess_file do |renderer, full_document|
12
+ if full_document =~ FILE_DIRECTIVE_REGEXP
13
+ if $1 == "md" and $2 == "plaintext"
14
+ full_document = "```\n#{full_document.gsub(FILE_DIRECTIVE_REGEXP, "")}\n```"
15
+ end
21
16
  end
22
- end
23
-
24
- if respond_to? :preprocess_without_plaintext
25
- preprocess_without_plaintext(full_document)
26
- else
27
17
  full_document
28
18
  end
29
19
  end
@@ -1,7 +1,9 @@
1
1
  class String
2
- # @param (String) req Gem version requirement
3
- # @return (Boolean) true if the given requirement is satisfied by the current
4
- # String
2
+ # @param req [String] Gem version requirement
3
+ # @return [true] if the given requirement is satisfied by the current String
4
+ # @return [false] otherwise
5
+ # @see http://rubydoc.info/github/rubygems/rubygems/Gem/Requirement Gem::Requirement
6
+ # @see http://rubydoc.info/github/rubygems/rubygems/Gem/Version Gem::Version
5
7
  def version_match?(req)
6
8
  Gem::Requirement.new(req) =~ Gem::Version.new(self)
7
9
  end
@@ -0,0 +1,41 @@
1
+ require "forwardable"
2
+ require "active_support/core_ext/string/starts_ends_with"
3
+ require "active_support/core_ext/string/inquiry"
4
+
5
+ class Symbol
6
+ extend Forwardable
7
+
8
+ def_delegators :to_s, :inquiry, :ends_with?
9
+
10
+ # @!method inquiry()
11
+ # Allows for any symbol to be "inquired" with a call ending with a `?`
12
+ #
13
+ # @return [true] if the method name matches the Symbol
14
+ # @return [false] otherwise
15
+ # @example
16
+ # :foo.foo? => true
17
+ # :foo.bar? => false
18
+ # @example Error
19
+ # :foo.foo => raises NoMethodError
20
+ # @see http://api.rubyonrails.org/v3.2.5/classes/String.html#method-i-inquiry
21
+ # String#inquiry in ActiveSupport
22
+
23
+ # @!method ends_with?(str)
24
+ # Check that the Symbol ends with the given String
25
+ #
26
+ # @param str [String] string to check for
27
+ # @return [true] if the Symbol ends with the given String
28
+ # @return [false] otherwise
29
+ # @see http://api.rubyonrails.org/v3.2.5 String#ends_with? in ActiveSupport
30
+
31
+ private
32
+
33
+ # Passes method names ending with `?` through to `#to_s.inquiry`
34
+ def method_missing(method_name, *arguments, &block)
35
+ if arguments.empty? and block.nil? and method_name.ends_with?("?")
36
+ self.inquiry.send(method_name)
37
+ else
38
+ super
39
+ end
40
+ end
41
+ end
@@ -1,19 +1,27 @@
1
+ # Copyright (c) 2012 MaxMedia and Travis Warlick
2
+ # Licensed under the MIT License (see LICENSE)
3
+
1
4
  require 'bundler'
5
+ require 'pathname'
6
+ require 'pp'
2
7
 
3
8
  module Dionysus
4
9
  module TravisCI
5
10
  class GemfileGenerator
6
11
  def initialize(gemfile)
7
- @definition = Bundler::Dsl.new
8
- @definition.instance_eval(Bundler.read_file(gemfile), "Gemfile", 1)
12
+ @definition = load_definition(gemfile)
13
+ @gemspec = load_gemspec(gemfile)
9
14
  end
10
15
 
11
16
  def generate(filename, options={})
17
+ Pathname.new(filename).dirname.mkpath
18
+
12
19
  File.open(filename, "w") do |f|
13
20
  f.puts %(source "http://rubygems.org")
14
21
 
15
22
  @definition.dependencies.each do |dep|
16
- next if exclude_by_group?(dep, :default, options[:without])
23
+ next if dep.name == @gemspec.name
24
+ next if exclude_by_group?(dep, options[:without])
17
25
  f.puts dependency_line(dep)
18
26
  end
19
27
 
@@ -49,7 +57,13 @@ module Dionysus
49
57
 
50
58
  if dep.source and dep.source.is_a?(Bundler::Source::Git)
51
59
  ln << %(:git => "%s")%[dep.source.options["git"]]
52
- ln << %(:branch => "%s")%[dep.source.options["branch"]]
60
+ %w[branch ref tag].each do |key|
61
+ if dep.source.options[key]
62
+ ln << %(%p => "%s")%[key.to_sym, dep.source.options[key]]
63
+ end
64
+ end
65
+ elsif dep.source and dep.source.is_a?(Bundler::Source::Path)
66
+ raise "Cannot create Gemfiles for Travis-CI with :path gems"
53
67
  elsif dep.source
54
68
  raise "Unknown source type: %s"%[dep.source.class]
55
69
  end
@@ -62,6 +76,22 @@ module Dionysus
62
76
  without = without.compact.flatten
63
77
  !(dep.groups & without).empty?
64
78
  end
79
+
80
+ def load_definition(gemfile)
81
+ Bundler::Dsl.new.tap do |dsl|
82
+ dsl.instance_eval(Bundler.read_file(gemfile), "Gemfile", 1)
83
+ end
84
+ end
85
+
86
+ def load_gemspec(gemfile)
87
+ gemspecs = Dir[ Pathname(gemfile).dirname.join("*.gemspec") ]
88
+ if gemspecs.empty?
89
+ raise "Gemspec not found in same directory as %p"%[gemfile]
90
+ elsif gemspecs.length > 1
91
+ warn "Multiple gemspecs found, but only one is supported. Using %p."%[gemspecs.first]
92
+ end
93
+ Bundler.load_gemspec(gemspecs.first)
94
+ end
65
95
  end
66
96
  end
67
97
  end
@@ -1,3 +1,3 @@
1
1
  module Dionysus
2
- VERSION = "2.1.0"
2
+ VERSION = "2.2.0.0.pre1"
3
3
  end
@@ -0,0 +1,20 @@
1
+ require "spec_helper"
2
+ require "dionysus/array/assert_types"
3
+
4
+ describe Array do
5
+ subject { [1, Object.new, "foo"] }
6
+
7
+ describe "#assert_types" do
8
+ it { subject.assert_types(Integer, Object, String).should be_true }
9
+
10
+ it "should require matching lengths" do
11
+ expect { subject.assert_types(Symbol) }.
12
+ to raise_error(ArgumentError, "Number of arguments must match length of Array")
13
+ end
14
+
15
+ it "should require matching types" do
16
+ expect { subject.assert_types(Integer, Object, Symbol) }.
17
+ to raise_error(ArgumentError, "Value at index 2 expected to be a Symbol")
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,26 @@
1
+ require 'spec_helper'
2
+ require 'dionysus/symbol/inquiry'
3
+
4
+ describe Symbol do
5
+ subject { :foo }
6
+
7
+ describe "#[inquiry]?" do
8
+ it "should pass-through without an ending '?'" do
9
+ expect { subject.foo }.to raise_error NoMethodError, "undefined method `foo' for :foo:Symbol"
10
+ end
11
+
12
+ it "should return false anything with an ending '?'" do
13
+ subject.blah?.should be_false
14
+ subject.should_not respond_to(:blah?)
15
+ 7.times do # 7 is a good prime-number :)
16
+ method_name = Faker::Lorem.characters(4)+"?"
17
+ subject.send(method_name).should be_false
18
+ subject.should_not respond_to(method_name)
19
+ end
20
+ end
21
+
22
+ it "should be true with it's own name'" do
23
+ subject.foo?.should be_true
24
+ end
25
+ end
26
+ end
data/spec/spec_helper.rb CHANGED
@@ -1,19 +1,20 @@
1
1
  require 'rubygems'
2
- require 'simplecov'
3
- SimpleCov.start do
4
- add_filter "/lib/dionysus/version.rb"
5
- add_filter "/spec/"
2
+
3
+ if RUBY_VERSION =~ /^1\.9\./
4
+ require 'simplecov'
5
+ SimpleCov.start do
6
+ add_filter "/lib/dionysus/version.rb"
7
+ add_filter "/spec/"
8
+ end
6
9
  end
7
10
 
8
11
  require 'bundler'
9
12
 
10
- require 'simplecov'
11
- SimpleCov.start
12
-
13
13
  Bundler.require :default, :test
14
14
 
15
15
  Dir[File.expand_path("../support/**/*.rb", __FILE__)].each {|f| require f}
16
16
 
17
17
  RSpec.configure do |config|
18
18
  config.mock_with :mocha
19
+ config.order = "random"
19
20
  end
metadata CHANGED
@@ -1,15 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dionysus
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.0
5
- prerelease:
4
+ version: 2.2.0.0.pre1
5
+ prerelease: 8
6
6
  platform: ruby
7
7
  authors:
8
8
  - Travis D. Warlick, Jr.
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-06-28 00:00:00.000000000 Z
12
+ date: 2012-09-04 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activesupport
@@ -34,15 +34,25 @@ executables: []
34
34
  extensions: []
35
35
  extra_rdoc_files:
36
36
  - README.md
37
+ - CONTRIBUTORS.md
37
38
  - LICENSE
38
39
  - docs/CHANGELOG.md
39
40
  - docs/ROADMAP.md
41
+ - docs/STANDARDS.md
42
+ - docs/VERSIONING.md
40
43
  files:
44
+ - lib/dionysus/array/assert_types.rb
41
45
  - lib/dionysus/configuration_callbacks.rb
46
+ - lib/dionysus/decoration.rb
47
+ - lib/dionysus/forwardable_to_class.rb
48
+ - lib/dionysus/forwardable_with_return.rb
49
+ - lib/dionysus/module/class_attr_typed.rb
50
+ - lib/dionysus/module/class_dsl_attr.rb
42
51
  - lib/dionysus/redcarpet/includes.rb
43
52
  - lib/dionysus/redcarpet/plaintext.rb
44
53
  - lib/dionysus/redcarpet.rb
45
54
  - lib/dionysus/string/version_match.rb
55
+ - lib/dionysus/symbol/inquiry.rb
46
56
  - lib/dionysus/travisci/gemfile_generator.rb
47
57
  - lib/dionysus/version.rb
48
58
  - lib/dionysus.rb
@@ -50,15 +60,20 @@ files:
50
60
  - Rakefile
51
61
  - description.md
52
62
  - README.md
63
+ - CONTRIBUTORS.md
53
64
  - LICENSE
54
65
  - docs/CHANGELOG.md
55
66
  - docs/ROADMAP.md
67
+ - docs/STANDARDS.md
68
+ - docs/VERSIONING.md
69
+ - spec/lib/array/assert_types_spec.rb
56
70
  - spec/lib/dionysus_spec.rb
57
71
  - spec/lib/string/version_match_spec.rb
72
+ - spec/lib/symbol/inquiry_spec.rb
58
73
  - spec/spec_helper.rb
59
74
  homepage: http://tekwiz.github.com/dionysus
60
75
  licenses:
61
- - Apache 2.0
76
+ - MIT
62
77
  post_install_message:
63
78
  rdoc_options:
64
79
  - --main
@@ -74,9 +89,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
74
89
  required_rubygems_version: !ruby/object:Gem::Requirement
75
90
  none: false
76
91
  requirements:
77
- - - ! '>='
92
+ - - ! '>'
78
93
  - !ruby/object:Gem::Version
79
- version: '0'
94
+ version: 1.3.1
80
95
  requirements: []
81
96
  rubyforge_project:
82
97
  rubygems_version: 1.8.24
@@ -84,7 +99,9 @@ signing_key:
84
99
  specification_version: 3
85
100
  summary: A helpful set of utility classes, generators, and command-line tools.
86
101
  test_files:
102
+ - spec/lib/array/assert_types_spec.rb
87
103
  - spec/lib/dionysus_spec.rb
88
104
  - spec/lib/string/version_match_spec.rb
105
+ - spec/lib/symbol/inquiry_spec.rb
89
106
  - spec/spec_helper.rb
90
107
  has_rdoc: