attributes_dsl 0.0.1
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.
- checksums.yaml +7 -0
- data/.coveralls.yml +2 -0
- data/.gitignore +9 -0
- data/.metrics +9 -0
- data/.rspec +2 -0
- data/.rubocop.yml +2 -0
- data/.travis.yml +20 -0
- data/.yardopts +3 -0
- data/CHANGELOG.md +3 -0
- data/Gemfile +16 -0
- data/Guardfile +14 -0
- data/LICENSE +21 -0
- data/README.md +209 -0
- data/Rakefile +39 -0
- data/attributes_dsl.gemspec +26 -0
- data/benchmark/run.rb +122 -0
- data/config/metrics/STYLEGUIDE +219 -0
- data/config/metrics/cane.yml +5 -0
- data/config/metrics/churn.yml +6 -0
- data/config/metrics/flay.yml +2 -0
- data/config/metrics/metric_fu.yml +14 -0
- data/config/metrics/reek.yml +1 -0
- data/config/metrics/roodi.yml +24 -0
- data/config/metrics/rubocop.yml +72 -0
- data/config/metrics/saikuro.yml +3 -0
- data/config/metrics/simplecov.yml +6 -0
- data/config/metrics/yardstick.yml +37 -0
- data/lib/attributes_dsl.rb +98 -0
- data/lib/attributes_dsl/attribute.rb +69 -0
- data/lib/attributes_dsl/attributes.rb +73 -0
- data/lib/attributes_dsl/version.rb +9 -0
- data/spec/integration/attributes_dsl_spec.rb +51 -0
- data/spec/spec_helper.rb +12 -0
- data/spec/unit/attribute_spec.rb +126 -0
- data/spec/unit/attributes_spec.rb +76 -0
- metadata +138 -0
@@ -0,0 +1,219 @@
|
|
1
|
+
= Ruby Style Guide
|
2
|
+
|
3
|
+
Adapted from Dan Kubb's Ruby Style Guide
|
4
|
+
https://github.com/dkubb/styleguide/blob/master/RUBY-STYLE
|
5
|
+
|
6
|
+
== Commiting:
|
7
|
+
|
8
|
+
* Write descriptive commit messages, following the pattern:
|
9
|
+
|
10
|
+
[TYPE] name
|
11
|
+
|
12
|
+
The message, describing the changes being made
|
13
|
+
|
14
|
+
* Use the types below to mark commits:
|
15
|
+
|
16
|
+
- NEW - for adding new features, or backward-compatible changes;
|
17
|
+
- CHANGE - for backward-incompatible changes;
|
18
|
+
- BUG FIX - for fixing bugs;
|
19
|
+
- INTERNAL - for other changes not affecting the API, including changes in documentaton, metrics etc.;
|
20
|
+
- VERSION - for version changes.
|
21
|
+
|
22
|
+
* Always separate commits of different types.
|
23
|
+
|
24
|
+
* Try to separate various features from each other.
|
25
|
+
|
26
|
+
* Include unit tests to the same commit as the code. Ensure the code is 100% covered (use mutant!)
|
27
|
+
|
28
|
+
* Run all tests before making a commit.
|
29
|
+
Never ever commit the code that breaks unit tests.
|
30
|
+
|
31
|
+
* Use metric (run `rake check`) before making a commit.
|
32
|
+
|
33
|
+
* Do refactoring before making a commit. Best writing is rewriting.
|
34
|
+
|
35
|
+
* Follow semantic versioning.
|
36
|
+
|
37
|
+
http://semver.org/
|
38
|
+
|
39
|
+
* For versions name the commit after a version number, following the pattern:
|
40
|
+
|
41
|
+
VERSION 1.0.0-rc2
|
42
|
+
|
43
|
+
|
44
|
+
== Formatting:
|
45
|
+
|
46
|
+
* Use UTF-8. Declare encoding in the first line of every file.
|
47
|
+
|
48
|
+
# encoding: utf-8
|
49
|
+
|
50
|
+
* For every new class or method add comment with your name and email.
|
51
|
+
|
52
|
+
# @author John Johnes <john.johnes@example.com>
|
53
|
+
|
54
|
+
This is necessary for others could send you they changes to review.
|
55
|
+
|
56
|
+
* Use 2 space indent, no tabs.
|
57
|
+
|
58
|
+
* Use Unix-style line endings.
|
59
|
+
|
60
|
+
* Use spaces around operators, after commas, colons and semicolons,
|
61
|
+
around { and before }.
|
62
|
+
|
63
|
+
* No spaces after (, [ and before ], ).
|
64
|
+
|
65
|
+
* Align `when` and `else` with `case`.
|
66
|
+
|
67
|
+
* Use an empty line before the return value of a method (unless it
|
68
|
+
only has one line), and an empty line between defs.
|
69
|
+
|
70
|
+
* Use empty lines to break up a long method into logical paragraphs.
|
71
|
+
|
72
|
+
* Keep lines fewer than 80 characters.
|
73
|
+
|
74
|
+
* Strip trailing whitespace.
|
75
|
+
|
76
|
+
|
77
|
+
== Syntax:
|
78
|
+
|
79
|
+
* Write for the earliest version supported by the gem.
|
80
|
+
|
81
|
+
* Use double quotes
|
82
|
+
|
83
|
+
http://viget.com/extend/just-use-double-quoted-ruby-strings
|
84
|
+
|
85
|
+
* Use def with parentheses when there are arguments.
|
86
|
+
|
87
|
+
* Never use for, unless you exactly know why.
|
88
|
+
|
89
|
+
* Never use then, except in case statements.
|
90
|
+
|
91
|
+
* Use when x then ... for one-line cases.
|
92
|
+
|
93
|
+
* Use &&/|| for boolean expressions, and/or for control flow. (Rule of thumb: If you have to use outer parentheses, you are using the wrong operators.)
|
94
|
+
|
95
|
+
* Avoid double negation (!!), unless Null Objects are expected.
|
96
|
+
|
97
|
+
http://devblog.avdi.org/2011/05/30/null-objects-and-falsiness
|
98
|
+
|
99
|
+
* Avoid multiline ?:, use if.
|
100
|
+
|
101
|
+
* Use {...} when defining blocks on one line. Use do...end for multiline blocks.
|
102
|
+
|
103
|
+
* Avoid return where not required.
|
104
|
+
|
105
|
+
* Use ||= freely.
|
106
|
+
|
107
|
+
* Use OO regexps, and avoid =~ $0-9, $~, $` and $' when possible.
|
108
|
+
|
109
|
+
* Do not use Enumerable#inject when the "memo" object does not change between iterations, use Enumerable#each_with_object instead.
|
110
|
+
|
111
|
+
* Prefer `fetch` to `[]` syntax. Prefer block syntax to the second argument of `fetch`.
|
112
|
+
|
113
|
+
|
114
|
+
== Naming:
|
115
|
+
|
116
|
+
* Use snake_case for methods.
|
117
|
+
|
118
|
+
* Use CamelCase for classes and modules. (Keep acronyms like HTTP, RFC, XML uppercase.)
|
119
|
+
|
120
|
+
* Use SCREAMING_SNAKE_CASE for other constants.
|
121
|
+
|
122
|
+
* Do not use single letter variable names. Avoid uncommunicative names.
|
123
|
+
|
124
|
+
* Use consistent variable names. Try to keep the variable names close to the object class name.
|
125
|
+
|
126
|
+
* Use names prefixed with _ for unused variables.
|
127
|
+
|
128
|
+
* When defining a predicate method that compares against another object of a similar type, name the argument "other".
|
129
|
+
|
130
|
+
* Prefer `map` over `collect`, `detect` over `find`, `select` over `find_all`.
|
131
|
+
|
132
|
+
* Prefer `def self.method` to singleton methods.
|
133
|
+
|
134
|
+
* Avoid alias when alias_method will do.
|
135
|
+
|
136
|
+
|
137
|
+
== Comments:
|
138
|
+
|
139
|
+
* Use YARD and its conventions for API documentation. Don't put an empty line between the comment block and the def.
|
140
|
+
|
141
|
+
* Comments longer than a word are capitalized and use punctuation. Use one space after periods.
|
142
|
+
|
143
|
+
* Avoid superfluous comments.
|
144
|
+
|
145
|
+
|
146
|
+
== Code structuring:
|
147
|
+
|
148
|
+
* Break code into packages, decoupled from the environment.
|
149
|
+
|
150
|
+
* Wrap packages into gems.
|
151
|
+
|
152
|
+
* Inject dependencies explicitly. Leave all outer references on the border of any package. Inside the package use internal references only.
|
153
|
+
|
154
|
+
* Follow SOLID principles.
|
155
|
+
|
156
|
+
http://en.wikipedia.org/wiki/SOLID_(object-oriented_design)
|
157
|
+
|
158
|
+
* Only give a method one purpose for existing.
|
159
|
+
|
160
|
+
If you pass in a boolean to a method, what you're saying is that this method has two different behaviours. Just split it into two single purpose methods.
|
161
|
+
|
162
|
+
If you have to use the words "AND" or "OR" to describe what the method does it probably does too much.
|
163
|
+
|
164
|
+
* Avoid long methods. Try to keep them at no more than 6 lines long, and preferably 4 or less.
|
165
|
+
|
166
|
+
If sections of a method are logically separate by blank lines, then that's probably a sign that those sections should be split into separate methods.
|
167
|
+
|
168
|
+
* Avoid hashes-as-optional-parameters. Does the method do too much?
|
169
|
+
|
170
|
+
* Avoid long parameter lists.
|
171
|
+
|
172
|
+
* Add "global" methods to Kernel (if you have to) and make them private.
|
173
|
+
|
174
|
+
* Use OptionParser for parsing complex command line options and ruby -s for trivial command line options.
|
175
|
+
|
176
|
+
* Avoid needless metaprogramming.
|
177
|
+
|
178
|
+
|
179
|
+
== General:
|
180
|
+
|
181
|
+
* Code in a functional way, avoid mutation when it makes sense.
|
182
|
+
|
183
|
+
* Always freeze objects assigned to constants.
|
184
|
+
|
185
|
+
Freeze instances at the end of the `#initializer` method. Don't mutate the state of the instance after initialization.
|
186
|
+
|
187
|
+
Use either `deep_nine` or `adamantium` gems to make the object deeply frozen.
|
188
|
+
|
189
|
+
* Do not mutate arguments unless that is the purpose of the method.
|
190
|
+
|
191
|
+
* Try to have methods either return the state of the object and have
|
192
|
+
no side effects, or return self and have side effects. This is
|
193
|
+
otherwise known as Command-query separation (CQS):
|
194
|
+
|
195
|
+
http://en.wikipedia.org/wiki/Command-query_separation
|
196
|
+
|
197
|
+
* Try following TRUE heuristics by Sandi Metz
|
198
|
+
|
199
|
+
http://designisrefactoring.com/2015/02/08/introducing-sandi-metz-true/
|
200
|
+
|
201
|
+
* Do not mess around in core classes when writing libraries. Namespace your code inside the modules, or wrap core classes to decorators of your own.
|
202
|
+
|
203
|
+
* Do not program defensively.
|
204
|
+
|
205
|
+
http://www.erlang.se/doc/programming_rules.shtml#HDR11
|
206
|
+
|
207
|
+
* Keep the code simple.
|
208
|
+
|
209
|
+
* Don't overdesign.
|
210
|
+
|
211
|
+
* Don't underdesign.
|
212
|
+
|
213
|
+
* Avoid bugs.
|
214
|
+
|
215
|
+
* Read other style guides and apply the parts that don't dissent with this list.
|
216
|
+
|
217
|
+
* Be consistent.
|
218
|
+
|
219
|
+
* Use common sense.
|
@@ -0,0 +1,14 @@
|
|
1
|
+
---
|
2
|
+
folders: # The list of folders to be used by any metric.
|
3
|
+
- lib
|
4
|
+
metrics: # The list of allowed metrics. The other metrics are disabled.
|
5
|
+
- cane
|
6
|
+
- churn
|
7
|
+
- flay
|
8
|
+
- flog
|
9
|
+
- reek
|
10
|
+
- roodi
|
11
|
+
- saikuro
|
12
|
+
format: html
|
13
|
+
output: tmp/metric_fu
|
14
|
+
verbose: false
|
@@ -0,0 +1 @@
|
|
1
|
+
---
|
@@ -0,0 +1,24 @@
|
|
1
|
+
---
|
2
|
+
AssignmentInConditionalCheck:
|
3
|
+
CaseMissingElseCheck:
|
4
|
+
ClassLineCountCheck:
|
5
|
+
line_count: 100
|
6
|
+
ClassNameCheck:
|
7
|
+
pattern: !ruby/regexp /^[A-Z][a-zA-Z0-9]*$/
|
8
|
+
ClassVariableCheck:
|
9
|
+
CyclomaticComplexityBlockCheck:
|
10
|
+
complexity: 3
|
11
|
+
CyclomaticComplexityMethodCheck:
|
12
|
+
complexity: 4
|
13
|
+
EmptyRescueBodyCheck:
|
14
|
+
ForLoopCheck:
|
15
|
+
MethodLineCountCheck:
|
16
|
+
line_count: 6
|
17
|
+
MethodNameCheck:
|
18
|
+
pattern: !ruby/regexp /^[\||\^|\&|\!]$|^[_a-z<>=\[|+-\/\*`]+[_a-z0-9_<>=~@\[\]]*[=!\?]?$/
|
19
|
+
ModuleLineCountCheck:
|
20
|
+
line_count: 100
|
21
|
+
ModuleNameCheck:
|
22
|
+
pattern: !ruby/regexp /^[A-Z][a-zA-Z0-9]*$/
|
23
|
+
ParameterNumberCheck:
|
24
|
+
parameter_count: 4
|
@@ -0,0 +1,72 @@
|
|
1
|
+
---
|
2
|
+
# settings added by the 'hexx-suit' module
|
3
|
+
# output: "tmp/rubocop"
|
4
|
+
# format: "html"
|
5
|
+
|
6
|
+
AllCops:
|
7
|
+
Exclude:
|
8
|
+
- '**/db/schema.rb'
|
9
|
+
|
10
|
+
Lint/HandleExceptions:
|
11
|
+
Exclude:
|
12
|
+
- '**/*_spec.rb'
|
13
|
+
|
14
|
+
Lint/RescueException:
|
15
|
+
Exclude:
|
16
|
+
- '**/*_spec.rb'
|
17
|
+
|
18
|
+
Style/AccessorMethodName:
|
19
|
+
Exclude:
|
20
|
+
- '**/*_spec.rb'
|
21
|
+
|
22
|
+
Style/AsciiComments:
|
23
|
+
Enabled: false
|
24
|
+
|
25
|
+
Style/ClassAndModuleChildren:
|
26
|
+
Enabled: false
|
27
|
+
|
28
|
+
Style/Documentation:
|
29
|
+
Enabled: false
|
30
|
+
|
31
|
+
Style/EmptyLinesAroundBlockBody:
|
32
|
+
Enabled: false
|
33
|
+
|
34
|
+
Style/EmptyLinesAroundClassBody:
|
35
|
+
Enabled: false
|
36
|
+
|
37
|
+
Style/EmptyLinesAroundMethodBody:
|
38
|
+
Enabled: false
|
39
|
+
|
40
|
+
Style/EmptyLinesAroundModuleBody:
|
41
|
+
Enabled: false
|
42
|
+
|
43
|
+
Style/EmptyLineBetweenDefs:
|
44
|
+
Enabled: false
|
45
|
+
|
46
|
+
Style/FileName:
|
47
|
+
Enabled: false
|
48
|
+
|
49
|
+
Style/RaiseArgs:
|
50
|
+
EnforcedStyle: compact
|
51
|
+
|
52
|
+
Style/SingleLineMethods:
|
53
|
+
Exclude:
|
54
|
+
- '**/*_spec.rb'
|
55
|
+
|
56
|
+
Style/SingleSpaceBeforeFirstArg:
|
57
|
+
Enabled: false
|
58
|
+
|
59
|
+
Style/SpecialGlobalVars:
|
60
|
+
Exclude:
|
61
|
+
- '**/Gemfile'
|
62
|
+
- '**/*.gemspec'
|
63
|
+
|
64
|
+
Style/StringLiterals:
|
65
|
+
EnforcedStyle: double_quotes
|
66
|
+
|
67
|
+
Style/StringLiteralsInInterpolation:
|
68
|
+
EnforcedStyle: double_quotes
|
69
|
+
|
70
|
+
Style/TrivialAccessors:
|
71
|
+
Exclude:
|
72
|
+
- '**/*_spec.rb'
|
@@ -0,0 +1,37 @@
|
|
1
|
+
---
|
2
|
+
# Settings added by the 'hexx-suit' gem
|
3
|
+
output: "tmp/yardstick/output.log"
|
4
|
+
path: "lib/**/*.rb"
|
5
|
+
rules:
|
6
|
+
ApiTag::Presence:
|
7
|
+
enabled: true
|
8
|
+
exclude: []
|
9
|
+
ApiTag::Inclusion:
|
10
|
+
enabled: true
|
11
|
+
exclude: []
|
12
|
+
ApiTag::ProtectedMethod:
|
13
|
+
enabled: true
|
14
|
+
exclude: []
|
15
|
+
ApiTag::PrivateMethod:
|
16
|
+
enabled: false
|
17
|
+
exclude: []
|
18
|
+
ExampleTag:
|
19
|
+
enabled: true
|
20
|
+
exclude: []
|
21
|
+
ReturnTag:
|
22
|
+
enabled: true
|
23
|
+
exclude: []
|
24
|
+
Summary::Presence:
|
25
|
+
enabled: true
|
26
|
+
exclude: []
|
27
|
+
Summary::Length:
|
28
|
+
enabled: true
|
29
|
+
exclude: []
|
30
|
+
Summary::Delimiter:
|
31
|
+
enabled: true
|
32
|
+
exclude: []
|
33
|
+
Summary::SingleLine:
|
34
|
+
enabled: true
|
35
|
+
exclude: []
|
36
|
+
threshold: 100
|
37
|
+
verbose: false
|
@@ -0,0 +1,98 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require "equalizer"
|
4
|
+
require "ice_nine"
|
5
|
+
|
6
|
+
# Simple DSL for PORO attributes
|
7
|
+
#
|
8
|
+
# @api public
|
9
|
+
#
|
10
|
+
# @author Andrew Kozin <Andrew.Kozin@gmail.com>
|
11
|
+
#
|
12
|
+
module AttributesDSL
|
13
|
+
|
14
|
+
require_relative "attributes_dsl/attribute"
|
15
|
+
require_relative "attributes_dsl/attributes"
|
16
|
+
|
17
|
+
# The mutable collection of declared attributes
|
18
|
+
#
|
19
|
+
# @return [AttributeDSL::Attributes]
|
20
|
+
#
|
21
|
+
# @api private
|
22
|
+
#
|
23
|
+
def attributes
|
24
|
+
@attributes ||= Attributes.new
|
25
|
+
end
|
26
|
+
|
27
|
+
# Retisters an attribute by name, options and coercer
|
28
|
+
#
|
29
|
+
# @example
|
30
|
+
# class MyClass
|
31
|
+
# extend AttributeDSL
|
32
|
+
#
|
33
|
+
# attribute :foo, required: true do |value|
|
34
|
+
# value.to_i % 5
|
35
|
+
# end
|
36
|
+
#
|
37
|
+
# attribute :bar, default: :BAR
|
38
|
+
# end
|
39
|
+
#
|
40
|
+
# @param [#to_sym] name The unique name of the attribute
|
41
|
+
# @param [Proc] coercer The proc to coerce values (including the default ones)
|
42
|
+
# @param [Hash] options
|
43
|
+
#
|
44
|
+
# @option options [Boolean] :required
|
45
|
+
# Whether the attribute should be required by the +initializer+
|
46
|
+
# This option is ignored (set to +false+) when default value is provided
|
47
|
+
# @option options [Object] :default
|
48
|
+
# The default value for the attribute
|
49
|
+
#
|
50
|
+
# @return [undefined]
|
51
|
+
#
|
52
|
+
def attribute(name, options = {}, &coercer)
|
53
|
+
s_name = name.to_sym
|
54
|
+
@attributes = attributes.register(s_name, options, &coercer)
|
55
|
+
|
56
|
+
define_method(s_name) { attributes.fetch(s_name) }
|
57
|
+
end
|
58
|
+
|
59
|
+
# Object contstructor that filters hash of attributes
|
60
|
+
#
|
61
|
+
# @param [Hash] hash The hash of attributes to be assinged
|
62
|
+
#
|
63
|
+
# @return [Object]
|
64
|
+
#
|
65
|
+
# @raise [ArgumentError] in case a required attribute is missed
|
66
|
+
#
|
67
|
+
def new(hash)
|
68
|
+
super attributes.extract(hash)
|
69
|
+
end
|
70
|
+
|
71
|
+
# @private
|
72
|
+
def self.extended(klass)
|
73
|
+
# use __send__ for compatibility to 1.9.3 (where `.include` was private)
|
74
|
+
klass.__send__(:include, InstanceMethods)
|
75
|
+
end
|
76
|
+
|
77
|
+
# Defines instance methods for the hash of attributes and its initializer
|
78
|
+
module InstanceMethods
|
79
|
+
|
80
|
+
# @!attribute [r] attributes
|
81
|
+
#
|
82
|
+
# @return [Hash] the hash of initialized attributes
|
83
|
+
#
|
84
|
+
attr_reader :attributes
|
85
|
+
|
86
|
+
# Initializes the object and sets the hash of its [#attributes]
|
87
|
+
#
|
88
|
+
# Uses attributes prepared by [.new]
|
89
|
+
#
|
90
|
+
# @param [Hash] attributes
|
91
|
+
#
|
92
|
+
def initialize(attributes)
|
93
|
+
@attributes = attributes
|
94
|
+
end
|
95
|
+
|
96
|
+
end # module InstanceMethods
|
97
|
+
|
98
|
+
end # module AttributesDSL
|