auom 0.0.6 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. data/.circle.yml +4 -0
  2. data/.rubocop.yml +7 -0
  3. data/.travis.yml +2 -9
  4. data/Changelog.md +4 -0
  5. data/Gemfile +2 -2
  6. data/Gemfile.devtools +39 -32
  7. data/auom.gemspec +3 -4
  8. data/circle.yml +4 -0
  9. data/config/flay.yml +1 -1
  10. data/config/{site.reek → reek.yml} +12 -11
  11. data/config/rubocop.yml +89 -0
  12. data/lib/auom.rb +7 -325
  13. data/lib/auom/algebra.rb +13 -10
  14. data/lib/auom/equalization.rb +6 -2
  15. data/lib/auom/inspection.rb +22 -57
  16. data/lib/auom/relational.rb +4 -2
  17. data/lib/auom/unit.rb +324 -0
  18. data/spec/shared/incompatible_operation_behavior.rb +3 -1
  19. data/spec/shared/operation_behavior.rb +3 -2
  20. data/spec/shared/sunits_shared.rb +3 -1
  21. data/spec/spec_helper.rb +2 -0
  22. data/spec/unit/auom/algebra/add_spec.rb +8 -6
  23. data/spec/unit/auom/algebra/divide_spec.rb +26 -15
  24. data/spec/unit/auom/algebra/multiply_spec.rb +25 -15
  25. data/spec/unit/auom/algebra/substract_spec.rb +8 -6
  26. data/spec/unit/auom/equalization/equality_operator_spec.rb +5 -3
  27. data/spec/unit/auom/inspection/class_methods/prettify_unit_part_spec.rb +6 -4
  28. data/spec/unit/auom/inspection/inspect_spec.rb +15 -13
  29. data/spec/unit/auom/relational/greater_than_or_equal_to_predicate_spec.rb +3 -1
  30. data/spec/unit/auom/relational/greater_than_predicate_spec.rb +3 -1
  31. data/spec/unit/auom/relational/less_than_or_equal_to_predicate_spec.rb +3 -1
  32. data/spec/unit/auom/relational/less_than_predicate_spec.rb +3 -1
  33. data/spec/unit/auom/unit/assert_same_unit_spec.rb +5 -3
  34. data/spec/unit/auom/unit/class_methods/convert_spec.rb +8 -6
  35. data/spec/unit/auom/unit/class_methods/lookup_spec.rb +6 -4
  36. data/spec/unit/auom/unit/class_methods/new_spec.rb +22 -21
  37. data/spec/unit/auom/unit/class_methods/try_convert_spec.rb +6 -4
  38. data/spec/unit/auom/unit/class_methods/units_spec.rb +3 -1
  39. data/spec/unit/auom/unit/denominators_spec.rb +5 -3
  40. data/spec/unit/auom/unit/numerators_spec.rb +5 -3
  41. data/spec/unit/auom/unit/same_unit_predicate_spec.rb +5 -3
  42. data/spec/unit/auom/unit/scalar_spec.rb +4 -2
  43. data/spec/unit/auom/unit/unit +0 -0
  44. data/spec/unit/auom/unit/unit_spec.rb +5 -3
  45. data/spec/unit/auom/unit/unitless_predicate_spec.rb +9 -1
  46. metadata +13 -28
@@ -0,0 +1,4 @@
1
+ ---
2
+ test:
3
+ override:
4
+ - bundle exec rake ci
@@ -0,0 +1,7 @@
1
+ AllCops:
2
+ Includes:
3
+ - 'Gemfile'
4
+ Excludes:
5
+ - 'Gemfile.devtools'
6
+ - 'vendor/**'
7
+ - 'benchmarks/**'
@@ -1,13 +1,6 @@
1
1
  language: ruby
2
2
  script: 'bundle exec rake ci'
3
3
  rvm:
4
- - 1.8.7
5
4
  - 1.9.3
6
- - 1.9.2
7
- - jruby-18mode
8
- - jruby-19mode
9
- - rbx-18mode
10
- - rbx-19mode
11
- notifications:
12
- email:
13
- - mbj@seonic.net
5
+ - jruby-19mode
6
+ - rbx
@@ -1,3 +1,7 @@
1
+ # v0.1.0 2014-03-24
2
+
3
+ * [breaking-change] Drop support for 1.8
4
+
1
5
  # v0.0.6 2013-01-03
2
6
 
3
7
  * [change] Update dependencies
data/Gemfile CHANGED
@@ -4,5 +4,5 @@ source 'https://rubygems.org'
4
4
 
5
5
  gemspec
6
6
 
7
- gem 'devtools', :git => 'https://github.com/datamapper/devtools'
8
- eval File.read('Gemfile.devtools')
7
+ gem 'devtools', git: 'https://github.com/rom-rb/devtools.git'
8
+ eval_gemfile 'Gemfile.devtools'
@@ -1,55 +1,62 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  group :development do
4
- gem 'rake', '~> 10.0.3'
5
- gem 'rspec', '~> 2.13.0'
6
- gem 'yard', '~> 0.8.5'
4
+ gem 'rake', '~> 10.1.0'
5
+ gem 'rspec', '~> 2.14.1'
6
+ gem 'rspec-core', '~> 2.14.8'
7
+ gem 'yard', '~> 0.8.7'
8
+
9
+ platform :rbx do
10
+ gem 'rubysl-singleton', '~> 2.0.0'
11
+ end
7
12
  end
8
13
 
9
14
  group :yard do
10
- gem 'kramdown', '~> 0.14.2'
15
+ gem 'kramdown', '~> 1.3.2'
11
16
  end
12
17
 
13
18
  group :guard do
14
- gem 'guard', '~> 1.6.2'
15
- gem 'guard-bundler', '~> 1.0.0'
16
- gem 'guard-rspec', '~> 2.4.1'
19
+ gem 'guard', '~> 2.4.0'
20
+ gem 'guard-bundler', '~> 2.0.0'
21
+ gem 'guard-rspec', '~> 4.2.6'
22
+ gem 'guard-rubocop', '~> 1.0.2'
17
23
 
18
24
  # file system change event handling
19
- gem 'rb-fchange', '~> 0.0.6', :require => false
20
- gem 'rb-fsevent', '~> 0.9.3', :require => false
21
- gem 'rb-inotify', '~> 0.9.0', :require => false
22
-
23
- gem 'listen', '~> 0.7.3'
25
+ gem 'listen', '~> 2.5.0'
26
+ gem 'rb-fchange', '~> 0.0.6', require: false
27
+ gem 'rb-fsevent', '~> 0.9.3', require: false
28
+ gem 'rb-inotify', '~> 0.9.0', require: false
24
29
 
25
30
  # notification handling
26
- gem 'libnotify', '~> 0.8.0', :require => false
27
- gem 'rb-notifu', '~> 0.0.4', :require => false
28
- gem 'terminal-notifier-guard', '~> 1.5.3', :require => false
31
+ gem 'libnotify', '~> 0.8.0', require: false
32
+ gem 'rb-notifu', '~> 0.0.4', require: false
33
+ gem 'terminal-notifier-guard', '~> 1.5.3', require: false
29
34
  end
30
35
 
31
36
  group :metrics do
32
- gem 'flay', '~> 2.1.0'
33
- gem 'flog', '~> 3.2.2'
34
- gem 'reek', '~> 1.3.1'
35
- gem 'metric_fu-roodi', '~> 2.2.1'
36
- gem 'yardstick', '~> 0.9.4'
37
+ gem 'coveralls', '~> 0.7.0'
38
+ gem 'flay', '~> 2.4.0'
39
+ gem 'flog', '~> 4.2.0'
40
+ gem 'reek', '~> 1.3.2'
41
+ gem 'rubocop', '~> 0.18.1'
42
+ gem 'simplecov', '~> 0.8.2'
43
+ gem 'yardstick', '~> 0.9.9'
37
44
 
38
- platforms :ruby_18, :ruby_19 do
39
- # this indirectly depends on ffi which does not build on ruby-head
40
- gem 'yard-spellcheck', '~> 0.1.5'
45
+ platforms :mri do
46
+ gem 'mutant', '~> 0.5.7'
47
+ gem 'mutant-rspec', '~> 0.5.3'
41
48
  end
42
49
 
43
- platforms :mri_19, :rbx do
44
- gem 'mutant', '~> 0.2.20'
45
- end
46
-
47
- platforms :mri_19 do
48
- gem 'simplecov', '~> 0.7.1'
50
+ platforms :ruby_19, :ruby_20 do
51
+ gem 'yard-spellcheck', '~> 0.1.5'
49
52
  end
50
53
 
51
- platforms :rbx do
52
- gem 'pelusa', '~> 0.2.2'
54
+ platform :rbx do
55
+ gem 'json', '~> 1.8.1'
56
+ gem 'racc', '~> 1.4'
57
+ gem 'rubysl-logger', '~> 2.0.0'
58
+ gem 'rubysl-open-uri', '~> 2.0.0'
59
+ gem 'rubysl-prettyprint', '~> 2.0.2'
53
60
  end
54
61
  end
55
62
 
@@ -59,6 +66,6 @@ end
59
66
 
60
67
  platform :jruby do
61
68
  group :jruby do
62
- gem 'jruby-openssl', '~> 0.8.2'
69
+ gem 'jruby-openssl', '~> 0.8.5'
63
70
  end
64
71
  end
@@ -2,10 +2,10 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = 'auom'
5
- s.version = '0.0.6'
5
+ s.version = '0.1.0'
6
6
 
7
7
  s.authors = ['Markus Schirp']
8
- s.email = 'mbj@seonic.net'
8
+ s.email = 'mbj@schirp-dso.com'
9
9
  s.summary = 'Algebra (with) Units Of Measurement'
10
10
  s.homepage = 'http://github.com/mbj/auom'
11
11
 
@@ -16,6 +16,5 @@ Gem::Specification.new do |s|
16
16
 
17
17
  s.rubygems_version = '1.8.10'
18
18
 
19
- s.add_dependency('backports', [ '~> 3.0', '>= 3.0.3' ])
20
- s.add_dependency('equalizer', '~> 0.0.5')
19
+ s.add_dependency('equalizer', '~> 0.0.9')
21
20
  end
@@ -0,0 +1,4 @@
1
+ ---
2
+ test:
3
+ override:
4
+ - bundle exec rake ci
@@ -1,3 +1,3 @@
1
1
  ---
2
2
  threshold: 12
3
- total_score: 99.0
3
+ total_score: 87.0
@@ -6,7 +6,7 @@ UncommunicativeParameterName:
6
6
  - !ruby/regexp /^.$/
7
7
  - !ruby/regexp /[0-9]$/
8
8
  - !ruby/regexp /[A-Z]/
9
- LargeClass:
9
+ TooManyMethods:
10
10
  max_methods: 14
11
11
  enabled: true
12
12
  exclude: []
@@ -21,7 +21,7 @@ UncommunicativeMethodName:
21
21
  - !ruby/regexp /[A-Z]/
22
22
  LongParameterList:
23
23
  max_params: 2
24
- exclude:
24
+ exclude:
25
25
  - "AUOM::Unit#initialize" # 3 params
26
26
  - "AUOM::Unit#self.new" # 3 params
27
27
  - "AUOM::Unit#self.resolve" # 3 params
@@ -48,16 +48,16 @@ UncommunicativeModuleName:
48
48
  - !ruby/regexp /[0-9]$/
49
49
  NestedIterators:
50
50
  ignore_iterators: []
51
- exclude:
51
+ exclude:
52
52
  - AUOM::Unit#initialize # 2 levels
53
53
  enabled: true
54
54
  max_allowed_nesting: 1
55
- LongMethod:
56
- max_statements: 5
57
- exclude:
55
+ TooManyStatements:
56
+ max_statements: 6
57
+ exclude:
58
58
  - "AUOM::Inspection#pretty_unit" # 7 statements
59
59
  enabled: true
60
- Duplication:
60
+ DuplicateMethodCall:
61
61
  allow_calls: []
62
62
  exclude:
63
63
  - "AUOM::ClassMethods#new" # invalid detection
@@ -78,16 +78,17 @@ UncommunicativeVariableName:
78
78
  - !ruby/regexp /^.$/
79
79
  - !ruby/regexp /[0-9]$/
80
80
  - !ruby/regexp /[A-Z]/
81
- SimulatedPolymorphism:
81
+ RepeatedConditional:
82
82
  enabled: true
83
83
  max_ifs: 1
84
84
  DataClump:
85
85
  exclude: []
86
86
  enabled: true
87
- max_copies: 0
87
+ max_copies: 1
88
88
  min_clump_size: 2
89
- ControlCouple:
90
- exclude: []
89
+ ControlParameter:
90
+ exclude:
91
+ - AUOM::Unit#assert_same_unit
91
92
  enabled: true
92
93
  LongYieldList:
93
94
  max_params: 0
@@ -0,0 +1,89 @@
1
+ inherit_from: ../.rubocop.yml
2
+
3
+ # General note about rubocop.
4
+ # It does NOT allow to silence a specific rule violation.
5
+ # For that reason I sometimes have to disable a whole cop where
6
+ # I just tried to whitelist a specific occurence.
7
+
8
+
9
+ AllCops:
10
+ Includes:
11
+ - '../**/*.rake'
12
+ - 'Gemfile'
13
+ - 'Gemfile.triage'
14
+ - 'mutant.gemspec'
15
+
16
+ # Avoid parameter lists longer than five parameters.
17
+ ParameterLists:
18
+ Max: 3
19
+ CountKeywordArgs: true
20
+
21
+ # Avoid more than `Max` levels of nesting.
22
+ BlockNesting:
23
+ Max: 3
24
+
25
+ # Align with the style guide.
26
+ CollectionMethods:
27
+ PreferredMethods:
28
+ collect: 'map'
29
+ inject: 'reduce'
30
+ find: 'detect'
31
+ find_all: 'select'
32
+
33
+ MethodLength:
34
+ CountComments: false
35
+ Max: 17 # TODO: Bring down to 10
36
+
37
+ RegexpLiteral: # I do not agree %r(\A) is more readable than /\A/
38
+ Enabled: false
39
+
40
+ # Limit line length
41
+ LineLength:
42
+ Max: 124 # TODO: lower to 79
43
+
44
+ # Disable documentation checking until a class needs to be documented once
45
+ Documentation:
46
+ Enabled: false
47
+
48
+ # Do not favor modifier if/unless usage when you have a single-line body
49
+ IfUnlessModifier:
50
+ Enabled: false
51
+
52
+ # Allow case equality operator (in limited use within the specs)
53
+ CaseEquality:
54
+ Enabled: false
55
+
56
+ # Constants do not always have to use SCREAMING_SNAKE_CASE
57
+ ConstantName:
58
+ Enabled: false
59
+
60
+ # Not all trivial readers/writers can be defined with attr_* methods
61
+ TrivialAccessors:
62
+ Enabled: false
63
+
64
+ # And also have a differend opinion here
65
+ AndOr:
66
+ Enabled: false
67
+
68
+ # I like my raise
69
+ SignalException:
70
+ Enabled: false
71
+
72
+ # I need to chain optparse builder, else it is more ugly
73
+ MultilineBlockChain:
74
+ Enabled: false
75
+
76
+ ClassLength:
77
+ Max: 119
78
+
79
+ # I align private keywords with class body
80
+ IndentationWidth:
81
+ Enabled: false
82
+
83
+ # I like to have an empty line before closing the currently opened body
84
+ EmptyLinesAroundBody:
85
+ Enabled: false
86
+
87
+ # I like my style more
88
+ AccessModifierIndentation:
89
+ Enabled: false
@@ -1,332 +1,14 @@
1
+ # encoding: UTF-8
2
+
1
3
  require 'rational'
2
- require 'backports'
3
4
  require 'equalizer'
4
5
 
6
+ # Library namespace
7
+ module AUOM
8
+ end
9
+
5
10
  require 'auom/algebra'
6
11
  require 'auom/equalization'
7
12
  require 'auom/inspection'
8
13
  require 'auom/relational'
9
-
10
- # Library namespace
11
- module AUOM
12
- # A scalar with units
13
- class Unit
14
- include Equalizer.new(:scalar, :numerators, :denominators)
15
- include Algebra
16
- include Equalization
17
- include Inspection
18
- include Relational
19
-
20
- # Return scalar
21
- #
22
- # @example
23
- #
24
- # include AUOM
25
- # m = Unit.new(1, :meter)
26
- # m.scalar # => Rational(1, 1)
27
- #
28
- # @return [Rational]
29
- #
30
- # @api public
31
- #
32
- attr_reader :scalar
33
-
34
- # Return numerators
35
- #
36
- # @example
37
- #
38
- # include AUOM
39
- # m = Unit.new(1, :meter)
40
- # m.numerators # => [:meter]
41
- #
42
- # @return [Rational]
43
- #
44
- # @api public
45
- #
46
- attr_reader :numerators
47
-
48
- # Return denominators
49
- #
50
- # @example
51
- #
52
- # include AUOM
53
- # m = Unit.new(1, :meter)
54
- # m.denoninators # => []
55
- #
56
- # @return [Rational]
57
- #
58
- # @api public
59
- #
60
- attr_reader :denominators
61
-
62
- # Return unit descriptor
63
- #
64
- # @return [Array]
65
- #
66
- # @api public
67
- #
68
- # @example
69
- #
70
- # u = Unit.new(1, [:meter, :meter], :euro)
71
- # u.unit # => [[:meter, :meter], [:euro]]
72
- #
73
- attr_reader :unit
74
-
75
- # These constants can easily be changed
76
- # by an application specific subclass that overrides
77
- # AUOM::Unit.units with an own hash!
78
- UNITS = {
79
- :item => [1, :item],
80
- :liter => [1, :liter],
81
- :pack => [1, :pack],
82
- :can => [1, :can],
83
- :kilogramm => [1, :kilogramm],
84
- :euro => [1, :euro],
85
- :meter => [1, :meter],
86
- :kilometer => [1000, :meter]
87
- }.freeze
88
-
89
- # Return buildin units symbols
90
- #
91
- # @return [Hash]
92
- #
93
- # @api private
94
- #
95
- def self.units
96
- UNITS
97
- end
98
-
99
- # Check for unitless unit
100
- #
101
- # @return [true]
102
- # return true if unit is unitless
103
- #
104
- # @return [false]
105
- # return false if unit is NOT unitless
106
- #
107
- # @example
108
- #
109
- # Unit.new(1).unitless? # => true
110
- # Unit.new(1, :meter).unitless ? # => false
111
- #
112
- # @api public
113
- #
114
- def unitless?
115
- numerators.empty? and denominators.empty?
116
- end
117
-
118
- # Test if units are the same
119
- #
120
- # @param [Unit] other
121
- #
122
- # @return [true]
123
- # if units are the same
124
- #
125
- # @return [false]
126
- # otehrwise
127
- #
128
- # @example
129
- #
130
- # a = Unit.new(1)
131
- # b = Unit.new(1, :euro)
132
- # c = Unit.new(2, :euro)
133
- #
134
- # a.same_unit?(b) # => false
135
- # b.same_unit?(c) # => true
136
- #
137
- # @api public
138
- #
139
- def same_unit?(other)
140
- other.unit.eql?(unit)
141
- end
142
-
143
- # Instancitate a new unit
144
- #
145
- # @param [Rational] scalar
146
- # @param [Enumerable] numerators
147
- # @param [Enumerable] denominators
148
- #
149
- # @return [Unit]
150
- #
151
- # @example
152
- #
153
- # # A unitless unit
154
- # u = Unit.new(1)
155
- # u.unitless? # => true
156
- # u.scalar # => Rational(1, 1)
157
- #
158
- # # A unitless unit from string
159
- # u = Unit.new('1.5')
160
- # u.unitless? # => true
161
- # u.scalar # => Rational(3, 2)
162
- #
163
- # # A simple unit
164
- # u = Unit.new(1, :meter)
165
- # u.unitless? # => false
166
- # u.numerators # => [:meter]
167
- # u.scalar # => Rational(1, 1)
168
- #
169
- # # A complex unit
170
- # u = Unit.new(Rational(1, 3), :euro, :meter)
171
- # u.fractions? # => true
172
- # u.sclar # => Rational(1, 3)
173
- # u.inspect # => <AUOM::Unit @scalar=~0.3333 euro/meter>
174
- # u.unit # => [[:euro], [:meter]]
175
- #
176
- # @api public
177
- #
178
- def self.new(scalar, numerators=[], denominators=[])
179
- scalar = rational(scalar)
180
-
181
- scalar, numerators = resolve([*numerators], scalar, :*)
182
- scalar, denominators = resolve([*denominators], scalar, :/)
183
-
184
- # sorting on #to_s as Symbol#<=> is not present on 1.8.7
185
- super(scalar, *[numerators, denominators].map { |base| base.sort_by(&:to_s) }).freeze
186
- end
187
-
188
- # Assert units are the same
189
- #
190
- # @param [Unit] other
191
- #
192
- # @return [self]
193
- #
194
- # @api private
195
- #
196
- def assert_same_unit(other)
197
- unless same_unit?(other)
198
- raise ArgumentError, 'Incompatible units'
199
- end
200
-
201
- self
202
- end
203
-
204
- # Return converted operand or raise error
205
- #
206
- # @param [Object] operand
207
- #
208
- # @return [Unit]
209
- #
210
- # @raise [ArgumentError]
211
- # raises argument error in case operand cannot be converted
212
- #
213
- # @api private
214
- #
215
- def self.convert(operand)
216
- converted = try_convert(operand)
217
- unless converted
218
- raise ArgumentError, "Cannot convert #{operand.inspect} to #{self}"
219
- end
220
- converted
221
- end
222
-
223
- # Return converted operand or nil
224
- #
225
- # @param [Object] operand
226
- #
227
- # @return [Unit]
228
- # return unit in case operand can be converted
229
- #
230
- # @return [nil]
231
- # return nil in case operand can NOT be converted
232
- #
233
- # @api private
234
- #
235
- def self.try_convert(operand)
236
- case operand
237
- when self
238
- operand
239
- when Fixnum, Rational
240
- new(operand)
241
- else
242
- nil
243
- end
244
- end
245
-
246
-
247
- private
248
-
249
- # Initialize unit
250
- #
251
- # @param [Rational] scalar
252
- # @param [Enumerable] numerators
253
- # @param [Enumerable] denominators
254
- #
255
- # @api private
256
- #
257
- def initialize(scalar, numerators, denominators)
258
- @scalar = scalar
259
-
260
- [numerators, denominators].permutation do |left, right|
261
- left.delete_if { |item| right.delete_at(right.index(item) || right.length) }
262
- end
263
-
264
- @numerators = numerators.freeze
265
- @denominators = denominators.freeze
266
-
267
- @unit = [@numerators, @denominators].freeze
268
- @scalar.freeze
269
- end
270
-
271
- # Return rational converted from value
272
- #
273
- # @param [Object] value
274
- #
275
- # @return [Rationa]
276
- #
277
- # @raise [ArgumentError]
278
- # raises argument error when cannot be converted to a rational
279
- #
280
- # @api private
281
- #
282
- def self.rational(value)
283
- case value
284
- when Rational
285
- value
286
- when Fixnum
287
- Rational(value)
288
- else
289
- raise ArgumentError, "#{value.inspect} cannot be converted to rational"
290
- end
291
- end
292
-
293
- private_class_method :rational
294
-
295
- # Resolve unit component
296
- #
297
- # @param [Enumerable] components
298
- # @param [Symbol] operation
299
- #
300
- # @return [Array]
301
- #
302
- # @api private
303
- #
304
- def self.resolve(components, scalar, operation)
305
- resolved = components.map do |component|
306
- scale, component = lookup(component)
307
- scalar = scalar.send(operation, scale)
308
- component
309
- end
310
- [scalar, resolved]
311
- end
312
-
313
- private_class_method :resolve
314
-
315
- # Return unit information
316
- #
317
- # @param [Symbol] value
318
- # the unit to search for
319
- #
320
- # @return [Array]
321
- #
322
- # @api private
323
- #
324
- def self.lookup(value)
325
- units.fetch(value) do
326
- raise ArgumentError, "Unknown unit #{value.inspect}"
327
- end
328
- end
329
-
330
- private_class_method :lookup
331
- end
332
- end
14
+ require 'auom/unit'