assertion 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. checksums.yaml +7 -0
  2. data/.coveralls.yml +2 -0
  3. data/.gitignore +9 -0
  4. data/.metrics +9 -0
  5. data/.rspec +2 -0
  6. data/.rubocop.yml +2 -0
  7. data/.travis.yml +19 -0
  8. data/.yardopts +3 -0
  9. data/Gemfile +9 -0
  10. data/Guardfile +18 -0
  11. data/LICENSE +21 -0
  12. data/README.md +222 -0
  13. data/Rakefile +29 -0
  14. data/assertion.gemspec +27 -0
  15. data/config/metrics/STYLEGUIDE +230 -0
  16. data/config/metrics/cane.yml +5 -0
  17. data/config/metrics/churn.yml +6 -0
  18. data/config/metrics/flay.yml +2 -0
  19. data/config/metrics/metric_fu.yml +15 -0
  20. data/config/metrics/reek.yml +1 -0
  21. data/config/metrics/roodi.yml +24 -0
  22. data/config/metrics/rubocop.yml +72 -0
  23. data/config/metrics/saikuro.yml +3 -0
  24. data/config/metrics/simplecov.yml +6 -0
  25. data/config/metrics/yardstick.yml +37 -0
  26. data/lib/assertion.rb +79 -0
  27. data/lib/assertion/base.rb +186 -0
  28. data/lib/assertion/exceptions/invalid_error.rb +36 -0
  29. data/lib/assertion/exceptions/name_error.rb +29 -0
  30. data/lib/assertion/exceptions/not_implemented_error.rb +29 -0
  31. data/lib/assertion/inversion.rb +64 -0
  32. data/lib/assertion/inverter.rb +62 -0
  33. data/lib/assertion/state.rb +79 -0
  34. data/lib/assertion/transprocs/i18n.rb +55 -0
  35. data/lib/assertion/transprocs/inflector.rb +39 -0
  36. data/lib/assertion/transprocs/list.rb +30 -0
  37. data/lib/assertion/version.rb +9 -0
  38. data/spec/integration/assertion_spec.rb +50 -0
  39. data/spec/integration/en.yml +10 -0
  40. data/spec/spec_helper.rb +12 -0
  41. data/spec/unit/assertion/base_spec.rb +221 -0
  42. data/spec/unit/assertion/exceptions/invalid_error_spec.rb +40 -0
  43. data/spec/unit/assertion/exceptions/name_error_spec.rb +26 -0
  44. data/spec/unit/assertion/exceptions/not_implemented_error_spec.rb +26 -0
  45. data/spec/unit/assertion/inversion_spec.rb +89 -0
  46. data/spec/unit/assertion/inverter_spec.rb +80 -0
  47. data/spec/unit/assertion/state_spec.rb +224 -0
  48. data/spec/unit/assertion/transprocs/i18n/to_scope_spec.rb +19 -0
  49. data/spec/unit/assertion/transprocs/i18n/translate_spec.rb +28 -0
  50. data/spec/unit/assertion/transprocs/inflector/to_path_spec.rb +19 -0
  51. data/spec/unit/assertion/transprocs/inflector/to_snake_path_spec.rb +19 -0
  52. data/spec/unit/assertion/transprocs/inflector/to_snake_spec.rb +19 -0
  53. data/spec/unit/assertion/transprocs/list/symbolize_spec.rb +19 -0
  54. data/spec/unit/assertion_spec.rb +65 -0
  55. metadata +171 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 4a42bd3404b1c576172d51bb68c60070e5d0a11f
4
+ data.tar.gz: 652283f21156545c9aae42912cf06911e988f141
5
+ SHA512:
6
+ metadata.gz: 569103f1216ac675a37aa875464c988775f6b5ed8a03150da75db092b6e44b9e35467f192091025168004d7b53efa06cc648d1b45983d6e602ff80bd0a2b63d5
7
+ data.tar.gz: 22d4e650d8cdd775a479e92a66eca1b3e466cd61ebc650900910c1386ba6688525b2ff2fb1edbc2fa3e6076a02059921c2f589d48f448e51c543d28eaeda719a
@@ -0,0 +1,2 @@
1
+ ---
2
+ service_name: travis-ci
@@ -0,0 +1,9 @@
1
+ *.gem
2
+ *.lock
3
+ .bundle/
4
+ .yardoc/
5
+ coverage/
6
+ doc/
7
+ log/
8
+ pkg/
9
+ tmp/
@@ -0,0 +1,9 @@
1
+ # Settings for metric_fu and its packages are collected in the `config/metrics`
2
+ # and loaded by the Hexx::Suit::Metrics::MetricFu.
3
+
4
+ begin
5
+ require "hexx-suit"
6
+ Hexx::Suit::Metrics::MetricFu.load
7
+ rescue LoadError
8
+ puts "The 'hexx-suit' gem is not installed"
9
+ end
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --require spec_helper
2
+ --color
@@ -0,0 +1,2 @@
1
+ ---
2
+ inherit_from: "./config/metrics/rubocop.yml"
@@ -0,0 +1,19 @@
1
+ ---
2
+ language: ruby
3
+ bundler_args: --without metrics
4
+ cache: bundler
5
+ rvm:
6
+ - '1.9.3'
7
+ - '2.0'
8
+ - '2.1'
9
+ - '2.2'
10
+ - ruby-head
11
+ - rbx-2 --1.9
12
+ - rbx-2 --2.1
13
+ - jruby-1.7-19mode
14
+ - jruby-9.0.0.0.pre2
15
+ - jruby-head
16
+ matrix:
17
+ allow_failures:
18
+ - rvm: ruby-head
19
+ - rvm: jruby-head
@@ -0,0 +1,3 @@
1
+ --asset LICENSE
2
+ --exclude lib/assertion/version.rb
3
+ --output doc/api
data/Gemfile ADDED
@@ -0,0 +1,9 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec
4
+
5
+ group :metrics do
6
+ gem "hexx-suit", "~> 2.2" if RUBY_ENGINE == "ruby"
7
+ end
8
+
9
+ gem "transproc", github: "solnic/transproc", branch: "registry"
@@ -0,0 +1,18 @@
1
+ # encoding: utf-8
2
+
3
+ guard :rspec, cmd: "bundle exec rspec" do
4
+
5
+ watch(%r{^spec/.+_spec\.rb$})
6
+
7
+ watch(%r{^lib/assertion/(.+)\.rb}) do |m|
8
+ "spec/unit/assertion/#{m[1]}_spec.rb"
9
+ end
10
+
11
+ watch(%r{^lib/assertion/transproc.rb}) do
12
+ "spec/unit/assertion/transproc"
13
+ end
14
+
15
+ watch("lib/assertion.rb") { "spec" }
16
+ watch("spec/spec_helper.rb") { "spec" }
17
+
18
+ end # guard :rspec
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License
2
+
3
+ Copyright (c) 2015 Andrew Kozin (nepalez), andrew.kozin@gmail.com
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,222 @@
1
+ Assertion
2
+ =========
3
+
4
+ [![Gem Version](https://img.shields.io/gem/v/assertion.svg?style=flat)][gem]
5
+ [![Build Status](https://img.shields.io/travis/nepalez/assertion/master.svg?style=flat)][travis]
6
+ [![Dependency Status](https://img.shields.io/gemnasium/nepalez/assertion.svg?style=flat)][gemnasium]
7
+ [![Code Climate](https://img.shields.io/codeclimate/github/nepalez/assertion.svg?style=flat)][codeclimate]
8
+ [![Coverage](https://img.shields.io/coveralls/nepalez/assertion.svg?style=flat)][coveralls]
9
+ [![Inline docs](http://inch-ci.org/github/nepalez/assertion.svg)][inch]
10
+
11
+ [codeclimate]: https://codeclimate.com/github/nepalez/assertion
12
+ [coveralls]: https://coveralls.io/r/nepalez/assertion
13
+ [gem]: https://rubygems.org/gems/assertion
14
+ [gemnasium]: https://gemnasium.com/nepalez/assertion
15
+ [travis]: https://travis-ci.org/nepalez/assertion
16
+ [inch]: https://inch-ci.org/github/nepalez/assertion
17
+
18
+ Immutable assertions and validations for PORO.
19
+
20
+ Synopsis
21
+ --------
22
+
23
+ The primary goal of the gem is to decouple assertions about the objects, and their validations, from the data.
24
+
25
+ No `ActiveSupport`, no mutation of any instances.
26
+
27
+ ### Basic Usage
28
+
29
+ Define the assertion by inheriting it from the `Assertion::Base` class with attributes to which it should be applied.
30
+ Then implement the method `check` that should return the boolean value.
31
+
32
+ You can do it either in a classic style:
33
+
34
+ ```ruby
35
+ class IsAdult < Assertion::Base
36
+ attribute :age, :name
37
+
38
+ def check
39
+ age >= 18
40
+ end
41
+ end
42
+ ```
43
+
44
+ or using a builder for verbosity with the same result:
45
+
46
+ ```ruby
47
+ IsAdult = Assertion.about :age, :name do
48
+ age >= 18
49
+ end
50
+ ```
51
+
52
+ Define translations for both the *right* and *wrong* states of the assertion.
53
+
54
+ All the declared attributes are available (that's why we declared a `name` as an attribute):
55
+
56
+ ```yaml
57
+ # config/locales/en.yml
58
+ ---
59
+ en:
60
+ assertion:
61
+ is_adult:
62
+ right: "%{name} is already an adult (age %{age})"
63
+ wrong: "%{name} is a child yet (age %{age})"
64
+ ```
65
+
66
+ Check a state of a assertion for some argument(s), using class method `[]`:
67
+
68
+ ```ruby
69
+ john = { name: 'John', age: 10, gender: :male }
70
+
71
+ state = IsAdult[john]
72
+ # => #<Assertion::State @state=false, @messages=["John is a child yet (age 10)"]>
73
+ ```
74
+
75
+ The state supports `valid?`, `invalid?`, `messages` and `validate!` methods:
76
+
77
+ ```ruby
78
+ state.valid? # => false
79
+ state.invalid? # => true
80
+ state.messages # => ["John is a child yet (age 10)"]
81
+ state.validate! # => #<Assertion::InvalidError @messages=["John is a child yet (age 10)"]>
82
+ ```
83
+
84
+ ### Assertion Inversion
85
+
86
+ Use the `.not` *class* method to negate a assertion:
87
+
88
+ ```ruby
89
+ jack = { name: 'Jack', age: 21, gender: :male }
90
+
91
+ IsAdult.not[jack]
92
+ # => #<Assertion::State @state=false, @messages=["Jack is already an adult (age 21)"]>
93
+ ```
94
+
95
+ ### Composition of States
96
+
97
+ You can compose assertion states (results):
98
+
99
+ ```ruby
100
+ IsMale = Assertion.about :name, :gender do
101
+ gender == :male
102
+ end
103
+ ```
104
+
105
+ ```yaml
106
+ # config/locales/en.yml
107
+ ---
108
+ en:
109
+ assertion:
110
+ is_male:
111
+ right: "%{name} is a male"
112
+ wrong: "%{name} is a female"
113
+ ```
114
+
115
+ Use method `&` (or its aliases `+` or `>>`) to compose assertion states:
116
+
117
+ ```ruby
118
+ jane = { name: 'Jane', age: 16, gender: :female }
119
+
120
+ state = IsAdult[jane] & IsMale[jane]
121
+ # => #<Assertion::State @state=false, @messages=["Jane is a child yet (age 16)", "Jane is a female"]>
122
+ ```
123
+
124
+ Object Validation
125
+ -----------------
126
+
127
+ If you are used to "rails style" validations, provide a validator from assertions:
128
+
129
+ ```ruby
130
+ class User
131
+ include Virtus.model
132
+
133
+ attribute :name, String
134
+ attribute :age, Integer
135
+ attribute :gender, Symbol
136
+ end
137
+
138
+ class Women < User
139
+ def validate!
140
+ state.validate!
141
+ end
142
+
143
+ def state
144
+ IsAdult[attributes] & IsMale.not[attributes]
145
+ end
146
+ end
147
+
148
+ judy = Women.new(name: "Judy", age: 15, gender: :female)
149
+ judy.valdate!
150
+ # => #<Assertion::InvalidError @messages=["Judy is a child yet (age 15)"]>
151
+ ```
152
+
153
+ Edge Cases
154
+ ----------
155
+
156
+ You're expected to declare the `check` method for the assertion before applying it to some data.
157
+
158
+ Otherwise `Assertion::NotImplementedError` is raised:
159
+
160
+ ```ruby
161
+ IsAdult = Assertion.about :name, :age
162
+
163
+ IsAdult[name: "Jane", age: 10]
164
+ # => #<Assertion::NotImplementedError @message="IsAdult#check method not implemented">
165
+ ```
166
+
167
+ You cannot define attributes with names, that are already used as an istance methods:
168
+
169
+ ```ruby
170
+ IsAdult = Assertion.about :check, :call
171
+ # => #<Assertion::NameError @message="Wrong name(s) for attribute(s): check, call">
172
+ ```
173
+
174
+ Installation
175
+ ------------
176
+
177
+ Add this line to your application's Gemfile:
178
+
179
+ ```ruby
180
+ # Gemfile
181
+ gem "assertion"
182
+ ```
183
+
184
+ Then execute:
185
+
186
+ ```
187
+ bundle
188
+ ```
189
+
190
+ Or add it manually:
191
+
192
+ ```
193
+ gem install assertion
194
+ ```
195
+
196
+ Compatibility
197
+ -------------
198
+
199
+ Tested under rubies [compatible to MRI 1.9+](.travis.yml).
200
+
201
+ Uses [RSpec] 3.0+ for testing and [hexx-suit] for dev/test tools collection.
202
+
203
+ [RSpec]: http://rspec.org
204
+ [hexx-suit]: https://github.com/nepalez/hexx-suit
205
+
206
+ Contributing
207
+ ------------
208
+
209
+ * Read the [STYLEGUIDE](config/metrics/STYLEGUIDE)
210
+ * [Fork the project](https://github.com/nepalez/assertion)
211
+ * Create your feature branch (`git checkout -b my-new-feature`)
212
+ * Add tests for it (please, use [mutant] to verify the coverage!)
213
+ * Commit your changes (`git commit -am '[UPDATE] Add some feature'`)
214
+ * Push to the branch (`git push origin my-new-feature`)
215
+ * Create a new Pull Request
216
+
217
+ [mutant]: https://github.com/mbj/mutant
218
+
219
+ License
220
+ -------
221
+
222
+ See the [MIT LICENSE](LICENSE).
@@ -0,0 +1,29 @@
1
+ # encoding: utf-8
2
+ begin
3
+ require "bundler/setup"
4
+ rescue LoadError
5
+ puts "You must `gem install bundler` and `bundle install` to run rake tasks"
6
+ exit
7
+ end
8
+
9
+ # Loads bundler tasks
10
+ Bundler::GemHelper.install_tasks
11
+
12
+ # Loads the Hexx::RSpec and its tasks
13
+ begin
14
+ require "hexx-suit"
15
+ Hexx::Suit.install_tasks
16
+ rescue LoadError
17
+ require "hexx-rspec"
18
+ Hexx::RSpec.install_tasks
19
+ end
20
+
21
+ # Sets the Hexx::RSpec :test task to default
22
+ task :default do
23
+ system "bundle exec rspec spec"
24
+ end
25
+
26
+ desc "Runs mutation metric for testing"
27
+ task :mutant do
28
+ system "mutant -r ./spec/spec_helper --use rspec 'Assertion*' --fail-fast"
29
+ end
@@ -0,0 +1,27 @@
1
+ $:.push File.expand_path("../lib", __FILE__)
2
+ require "assertion/version"
3
+
4
+ Gem::Specification.new do |gem|
5
+
6
+ gem.name = "assertion"
7
+ gem.version = Assertion::VERSION.dup
8
+ gem.author = "Andrew Kozin"
9
+ gem.email = "andrew.kozin@gmail.com"
10
+ gem.homepage = "https://github.com/nepalez/assertion"
11
+ gem.summary = "PORO assertions and validation"
12
+ gem.license = "MIT"
13
+
14
+ gem.files = `git ls-files`.split($INPUT_RECORD_SEPARATOR)
15
+ gem.test_files = Dir["spec/**/*.rb"]
16
+ gem.extra_rdoc_files = Dir["README.md", "LICENSE"]
17
+ gem.require_paths = ["lib"]
18
+
19
+ gem.required_ruby_version = "~> 1.9"
20
+
21
+ gem.add_runtime_dependency "transproc", "~> 0.2"
22
+ gem.add_runtime_dependency "i18n", "~> 0.7"
23
+
24
+ gem.add_development_dependency "hexx-rspec", "~> 0.4"
25
+ gem.add_development_dependency "equalizer", "~> 0.0"
26
+
27
+ end # Gem::Specification
@@ -0,0 +1,230 @@
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
+ - FEATURE - for adding new features, or backward-compatible changes;
17
+ - CHANGE - for backward-incompatible changes;
18
+ - BUG FIX - for fixing bugs;
19
+ - REFACTORING - for other changes of the code not affecting the API;
20
+ - OTHER - for changes in documentaton, metrics etc, not touching the code;
21
+ - VERSION - for version changes.
22
+
23
+ * Always separate commits of different types (such as FEATURE and CHANGE).
24
+
25
+ * Try to separate various features from each other.
26
+
27
+ * Include specification to the same commit as the code.
28
+
29
+ * Run all tests before making a commit.
30
+ Never commit the code that break unit tests.
31
+
32
+ * Use metric (run `rake check`) before making a commit.
33
+
34
+ * Do refactoring before making a commit. Best writing is rewriting.
35
+
36
+ * Follow semantic versioning.
37
+
38
+ http://semver.org/
39
+
40
+ * For versions name the commit after a version number, following the pattern:
41
+
42
+ VERSION 1.0.0-rc2
43
+
44
+
45
+ == Formatting:
46
+
47
+ * Use UTF-8. Declare encoding in the first line of every file.
48
+
49
+ # encoding: utf-8
50
+
51
+ * Use 2 space indent, no tabs.
52
+
53
+ * Use Unix-style line endings.
54
+
55
+ * Use spaces around operators, after commas, colons and semicolons,
56
+ around { and before }.
57
+
58
+ * No spaces after (, [ and before ], ).
59
+
60
+ * Align `when` and `else` with `case`.
61
+
62
+ * Use an empty line before the return value of a method (unless it
63
+ only has one line), and an empty line between defs.
64
+
65
+ * Use empty lines to break up a long method into logical paragraphs.
66
+
67
+ * Keep lines fewer than 80 characters.
68
+
69
+ * Strip trailing whitespace.
70
+
71
+
72
+ == Syntax:
73
+
74
+ * Write for 2.0.
75
+
76
+ * Use double quotes
77
+
78
+ http://viget.com/extend/just-use-double-quoted-ruby-strings
79
+
80
+ * Use def with parentheses when there are arguments.
81
+
82
+ * Never use for, unless you exactly know why.
83
+
84
+ * Never use then, except in case statements.
85
+
86
+ * Use when x then ... for one-line cases.
87
+
88
+ * Use &&/|| for boolean expressions, and/or for control flow. (Rule
89
+ of thumb: If you have to use outer parentheses, you are using the
90
+ wrong operators.)
91
+
92
+ * Avoid double negation (!!), unless Null Objects are expected.
93
+
94
+ http://devblog.avdi.org/2011/05/30/null-objects-and-falsiness
95
+
96
+ * Avoid multiline ?:, use if.
97
+
98
+ * Use {...} when defining blocks on one line. Use do...end for multiline
99
+ blocks.
100
+
101
+ * Avoid return where not required.
102
+
103
+ * Use ||= freely.
104
+
105
+ * Use OO regexps, and avoid =~ $0-9, $~, $` and $' when possible.
106
+
107
+ * Do not use Enumerable#inject when the "memo" object does not change between
108
+ iterations, use Enumerable#each_with_object instead (in ruby 1.9,
109
+ active_support and backports).
110
+
111
+ * Prefer ENV.fetch to ENV[] syntax.
112
+ Prefer block syntax for ENV.fetch to usage of the second argument.
113
+
114
+
115
+ == Naming:
116
+
117
+ * Use snake_case for methods.
118
+
119
+ * Use CamelCase for classes and modules. (Keep acronyms like HTTP,
120
+ RFC, XML uppercase.)
121
+
122
+ * Use SCREAMING_SNAKE_CASE for other constants.
123
+
124
+ * Do not use single letter variable names. Avoid uncommunicative names.
125
+
126
+ * Use consistent variable names. Try to keep the variable names close
127
+ to the object class name.
128
+
129
+ * Use names prefixed with _ for unused variables.
130
+
131
+ * When defining a predicate method that compares against another object of
132
+ a similar type, name the argument "other".
133
+
134
+ * Prefer map over collect, detect over find, select over find_all.
135
+
136
+ * Use def self.method to define singleton methods.
137
+
138
+ * Avoid alias when alias_method will do.
139
+
140
+
141
+ == Comments:
142
+
143
+ * Use YARD and its conventions for API documentation. Don't put an
144
+ empty line between the comment block and the def.
145
+
146
+ * Comments longer than a word are capitalized and use punctuation.
147
+ Use one space after periods.
148
+
149
+ * Avoid superfluous comments.
150
+
151
+
152
+ == Code structuring:
153
+
154
+ * Break code into packages, decoupled from the environment.
155
+
156
+ * Wrap packages into gems.
157
+
158
+ * Inject dependencies explicitly.
159
+ Leave all outer references on the border of any package. Inside
160
+ the package use internal references only.
161
+
162
+ * Follow SOLID principles.
163
+
164
+ http://en.wikipedia.org/wiki/SOLID_(object-oriented_design)
165
+
166
+ * Only give a method one purpose for existing. If you pass in a boolean
167
+ to a method, what you're saying is that this method has two different
168
+ behaviours. Just split it into two single purpose methods. If you have
169
+ to use the words "AND" or "OR" to describe what the method does it
170
+ probably does too much.
171
+
172
+ * Avoid long methods.
173
+ Try to keep them at no more than 6 lines long, and preferably 4 or less.
174
+
175
+ If sections of a method are logically separate by blank lines, then
176
+ that's probably a sign that those sections should be split into separate
177
+ methods.
178
+
179
+ * Avoid hashes-as-optional-parameters. Does the method do too much?
180
+
181
+ * Avoid long parameter lists.
182
+
183
+ * Add "global" methods to Kernel (if you have to) and make them private.
184
+
185
+ * Use OptionParser for parsing complex command line options and
186
+ ruby -s for trivial command line options.
187
+
188
+ * Avoid needless metaprogramming.
189
+
190
+ * Always freeze objects assigned to constants.
191
+
192
+
193
+ == General:
194
+
195
+ * Code in a functional way, avoid mutation when it makes sense.
196
+
197
+ * Try to have methods either return the state of the object and have
198
+ no side effects, or return self and have side effects. This is
199
+ otherwise known as Command-query separation (CQS):
200
+
201
+ http://en.wikipedia.org/wiki/Command-query_separation
202
+
203
+ * Do not mutate arguments unless that is the purpose of the method.
204
+
205
+ * Try following TRUE heuristics by Sandi Metz
206
+
207
+ http://designisrefactoring.com/2015/02/08/introducing-sandi-metz-true/
208
+
209
+ * Do not mess around in core classes when writing libraries.
210
+ Namespace your code inside the modules, or wrap core classes to
211
+ decorators of your own.
212
+
213
+ * Do not program defensively.
214
+
215
+ http://www.erlang.se/doc/programming_rules.shtml#HDR11
216
+
217
+ * Keep the code simple.
218
+
219
+ * Don't overdesign.
220
+
221
+ * Don't underdesign.
222
+
223
+ * Avoid bugs.
224
+
225
+ * Read other style guides and apply the parts that don't dissent with
226
+ this list.
227
+
228
+ * Be consistent.
229
+
230
+ * Use common sense.