fractify 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: b7dee9a90b5b90e4e6b5279eadf795942cb424e3507d1e80c3d8fd2e95a1cc3b
4
+ data.tar.gz: a564de039fbc57637c3be967797d26a5f7216e16d1b9000439fc6de38fcd53e9
5
+ SHA512:
6
+ metadata.gz: 57de8465352800e17149a1d216ac311169bdc679e47e732970a694130ea8274a0b3c2bb4929fa64a24d9ce67862e9290162c0fb6e557fb9ba623be4515303e85
7
+ data.tar.gz: e28a9f15bf58ed3492fc8878400072fb8bbc22f3fea31b874fa5be9df76db6626dd03c7ee8c8b69fccc5b8a9128b8e12a84a0cfa2f4dc38a590c15ab56b33bca
data/.gitignore ADDED
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+ .byebug_history
data/.travis.yml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ sudo: false
3
+ language: ruby
4
+ cache: bundler
5
+ rvm:
6
+ - 2.5.5
7
+ before_install: gem install bundler -v 1.17.3
data/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
4
+
5
+ git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
6
+
7
+ # Specify your gem's dependencies in fractify.gemspec
8
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,84 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ fractify (1.0.0)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ addressable (2.7.0)
10
+ public_suffix (>= 2.0.2, < 5.0)
11
+ ast (2.4.0)
12
+ byebug (11.0.1)
13
+ docile (1.3.2)
14
+ faraday (1.0.0)
15
+ multipart-post (>= 1.2, < 3)
16
+ gitlab (4.14.1)
17
+ httparty (~> 0.14, >= 0.14.0)
18
+ terminal-table (~> 1.5, >= 1.5.1)
19
+ httparty (0.18.0)
20
+ mime-types (~> 3.0)
21
+ multi_xml (>= 0.5.2)
22
+ jaro_winkler (1.5.4)
23
+ mime-types (3.3.1)
24
+ mime-types-data (~> 3.2015)
25
+ mime-types-data (3.2019.1009)
26
+ minitest (5.14.0)
27
+ multi_xml (0.6.0)
28
+ multipart-post (2.1.1)
29
+ octokit (4.17.0)
30
+ faraday (>= 0.9)
31
+ sawyer (~> 0.8.0, >= 0.5.3)
32
+ parallel (1.19.1)
33
+ parser (2.7.0.5)
34
+ ast (~> 2.4.0)
35
+ pronto (0.10.0)
36
+ gitlab (~> 4.0, >= 4.0.0)
37
+ httparty (>= 0.13.7)
38
+ octokit (~> 4.7, >= 4.7.0)
39
+ rainbow (>= 2.2, < 4.0)
40
+ rugged (~> 0.24, >= 0.23.0)
41
+ thor (~> 0.20.0)
42
+ pronto-rubocop (0.10.0)
43
+ pronto (~> 0.10.0)
44
+ rubocop (~> 0.50, >= 0.49.1)
45
+ public_suffix (4.0.3)
46
+ rainbow (3.0.0)
47
+ rake (10.5.0)
48
+ rexml (3.2.4)
49
+ rubocop (0.80.1)
50
+ jaro_winkler (~> 1.5.1)
51
+ parallel (~> 1.10)
52
+ parser (>= 2.7.0.1)
53
+ rainbow (>= 2.2.2, < 4.0)
54
+ rexml
55
+ ruby-progressbar (~> 1.7)
56
+ unicode-display_width (>= 1.4.0, < 1.7)
57
+ ruby-progressbar (1.10.1)
58
+ rugged (0.99.0)
59
+ sawyer (0.8.2)
60
+ addressable (>= 2.3.5)
61
+ faraday (> 0.8, < 2.0)
62
+ simplecov (0.18.5)
63
+ docile (~> 1.1)
64
+ simplecov-html (~> 0.11)
65
+ simplecov-html (0.12.2)
66
+ terminal-table (1.8.0)
67
+ unicode-display_width (~> 1.1, >= 1.1.1)
68
+ thor (0.20.3)
69
+ unicode-display_width (1.6.1)
70
+
71
+ PLATFORMS
72
+ ruby
73
+
74
+ DEPENDENCIES
75
+ bundler (~> 1.17)
76
+ byebug
77
+ fractify!
78
+ minitest (~> 5.0)
79
+ pronto-rubocop
80
+ rake (~> 10.0)
81
+ simplecov
82
+
83
+ BUNDLED WITH
84
+ 1.17.3
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2020 Mateusz Drewniak
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.
data/README.md ADDED
@@ -0,0 +1,39 @@
1
+ # Fractify
2
+
3
+ Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/fractify`. To experiment with that code, run `bin/console` for an interactive prompt.
4
+
5
+ TODO: Delete this and the text above, and describe your gem
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'fractify'
13
+ ```
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install fractify
22
+
23
+ ## Usage
24
+
25
+ TODO: Write usage instructions here
26
+
27
+ ## Development
28
+
29
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
30
+
31
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
32
+
33
+ ## Contributing
34
+
35
+ Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/fractify.
36
+
37
+ ## License
38
+
39
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/gem_tasks'
4
+ require 'rake/testtask'
5
+
6
+ Rake::TestTask.new(:test) do |t|
7
+ t.libs << 'test'
8
+ t.libs << 'lib'
9
+ t.test_files = FileList['test/**/*_test.rb']
10
+ end
11
+
12
+ task default: :test
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "fractify"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
data/fractify.gemspec ADDED
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ lib = File.expand_path('lib', __dir__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+ require 'fractify/version'
6
+
7
+ Gem::Specification.new do |spec|
8
+ spec.name = 'fractify'
9
+ spec.version = Fractify::VERSION
10
+ spec.authors = ['Mateusz Drewniak']
11
+ spec.email = ['matmg24@gmail.com']
12
+
13
+ spec.summary = 'A few classes which make it possible to properly' \
14
+ ' handle common fractions in Ruby'
15
+ spec.homepage = 'https://gitlab.com/Verseth/fractify'
16
+ spec.license = 'MIT'
17
+
18
+ # Specify which files should be added to the gem when it is released.
19
+ # The `git ls-files -z` loads the files in the RubyGem
20
+ # that have been added into git.
21
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
22
+ `git ls-files -z`.split("\x0").reject do |f|
23
+ f.match(%r{^(test|spec|features)/})
24
+ end
25
+ end
26
+ spec.bindir = 'exe'
27
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
28
+ spec.require_paths = ['lib']
29
+
30
+ spec.add_development_dependency 'bundler', '~> 1.17'
31
+ spec.add_development_dependency 'byebug'
32
+ spec.add_development_dependency 'minitest', '~> 5.0'
33
+ spec.add_development_dependency 'pronto-rubocop'
34
+ spec.add_development_dependency 'rake', '~> 10.0'
35
+ spec.add_development_dependency 'simplecov'
36
+ end
@@ -0,0 +1,250 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Fractify
4
+ class Calculator
5
+ class << self
6
+ def evaluate(formula)
7
+ fraction_string = ''
8
+ current_rank = 0
9
+
10
+ incorrect_syntax, inside_of_a_fraction, minus_registered,
11
+ operator_awaiting_an_argument,
12
+ last_char_is_a_closed_bracket = false
13
+ at_least_one_fraction = false
14
+ fraction = nil
15
+
16
+ operators = Fractify::OperatorArray.new
17
+ index = 0
18
+
19
+ formula.each_char do |char|
20
+ if inside_of_a_fraction
21
+ if char == ')'
22
+ fraction_string = "(#{fraction_string})"
23
+ unless Fractify::Fraction.valid?(fraction_string)
24
+ incorrect_syntax = true
25
+ break
26
+ end
27
+
28
+ fraction = Fractify::Fraction.new(string: fraction_string)
29
+ operators.last.to_right = fraction if at_least_one_fraction
30
+
31
+ last_char_is_a_closed_bracket = true
32
+ fraction_string = ''
33
+ inside_of_a_fraction = false
34
+ operator_awaiting_an_argument = false
35
+ minus_registered = false
36
+ current_rank -= 3
37
+ at_least_one_fraction = true
38
+ else
39
+ fraction_string += char
40
+ end
41
+ elsif char == '('
42
+ if last_char_is_a_closed_bracket
43
+ incorrect_syntax = true
44
+ break
45
+ end
46
+ current_rank += 3
47
+ minus_registered = false if minus_registered
48
+ elsif char == ')'
49
+ last_char_is_a_closed_bracket = true
50
+ if current_rank.zero?
51
+ incorrect_syntax = true
52
+ break
53
+ end
54
+ current_rank -= 3
55
+ elsif Fractify::Fraction.numeric?(char) || char == '.'
56
+ if current_rank.zero?
57
+ incorrect_syntax = true
58
+ break
59
+ end
60
+
61
+ unless inside_of_a_fraction
62
+ inside_of_a_fraction = true
63
+ operator_awaiting_an_argument = false
64
+
65
+ if minus_registered
66
+ fraction_string += '-'
67
+ minus_registered = false
68
+ operators.pop
69
+ end
70
+ end
71
+ last_char_is_a_closed_bracket = false
72
+ fraction_string += char
73
+ elsif char == '-'
74
+ minus_registered = true
75
+ operator_awaiting_an_argument = true
76
+ operator = Fractify::Operator.new(char, calculate_rank(current_rank, char), fraction)
77
+ operators.push(operator)
78
+ last_char_is_a_closed_bracket = false
79
+ elsif char_is_an_operator(char)
80
+ if operator_awaiting_an_argument || inside_of_a_fraction
81
+ incorrect_syntax = true
82
+ break
83
+ end
84
+
85
+ last_char_is_a_closed_bracket = false
86
+ operator_awaiting_an_argument = true
87
+ operator = Fractify::Operator.new(char, calculate_rank(current_rank, char), fraction)
88
+ operators.push(operator)
89
+ elsif char != ' '
90
+ incorrect_syntax = true
91
+ break
92
+ end
93
+ index += 1
94
+ end
95
+
96
+ if operator_awaiting_an_argument || inside_of_a_fraction || incorrect_syntax
97
+ return nil
98
+ end
99
+
100
+ operators.sort_descending!
101
+ operators.each do |op|
102
+ case op.operator_character
103
+ when '+'
104
+ fraction = op.to_left + op.to_right
105
+ when '-'
106
+ fraction = op.to_left - op.to_right
107
+ when '*'
108
+ fraction = op.to_left * op.to_right
109
+ when '/'
110
+ fraction = op.to_left / op.to_right
111
+ when '^'
112
+ fraction = op.to_left**op.to_right
113
+ end
114
+ left = op.to_left
115
+ operators.each do |o|
116
+ o.to_left = fraction if o.to_left == left
117
+ o.to_right = fraction if o.to_right == left
118
+ end
119
+
120
+ op.executed!
121
+ if op != operators.last
122
+ new_op_index = find_operator_with_left(operators, op.to_right)
123
+ operators[new_op_index].to_left = op.to_left unless new_op_index.negative?
124
+ end
125
+ end
126
+
127
+ fraction
128
+ end
129
+
130
+ def valid?(formula)
131
+ fraction_string = ''
132
+ current_rank = 0
133
+
134
+ incorrect_syntax, inside_of_a_fraction, minus_registered,
135
+ operator_awaiting_an_argument,
136
+ last_char_is_a_closed_bracket = false
137
+ at_least_one_fraction = false
138
+ fraction = nil
139
+
140
+ operators = Fractify::OperatorArray.new
141
+ index = 0
142
+
143
+ formula.each_char do |char|
144
+ if inside_of_a_fraction
145
+ if char == ')'
146
+ fraction_string = "(#{fraction_string})"
147
+ unless Fractify::Fraction.valid?(fraction_string)
148
+ incorrect_syntax = true
149
+ break
150
+ end
151
+
152
+ last_char_is_a_closed_bracket = true
153
+ fraction_string = ''
154
+ inside_of_a_fraction = false
155
+ operator_awaiting_an_argument = false
156
+ minus_registered = false
157
+ current_rank -= 3
158
+ at_least_one_fraction = true
159
+ else
160
+ fraction_string += char
161
+ end
162
+ elsif char == '('
163
+ if last_char_is_a_closed_bracket
164
+ incorrect_syntax = true
165
+ break
166
+ end
167
+ current_rank += 3
168
+ minus_registered = false if minus_registered
169
+ elsif char == ')'
170
+ last_char_is_a_closed_bracket = true
171
+ if current_rank.zero?
172
+ incorrect_syntax = true
173
+ break
174
+ end
175
+ current_rank -= 3
176
+ elsif Fractify::Fraction.numeric?(char) || char == '.'
177
+ if current_rank.zero?
178
+ incorrect_syntax = true
179
+ break
180
+ end
181
+
182
+ unless inside_of_a_fraction
183
+ inside_of_a_fraction = true
184
+ operator_awaiting_an_argument = false
185
+
186
+ if minus_registered
187
+ fraction_string += '-'
188
+ minus_registered = false
189
+ end
190
+ end
191
+ last_char_is_a_closed_bracket = false
192
+ fraction_string += char
193
+ elsif char == '-'
194
+ minus_registered = true
195
+ operator_awaiting_an_argument = true
196
+ last_char_is_a_closed_bracket = false
197
+ elsif char_is_an_operator(char)
198
+ if operator_awaiting_an_argument || inside_of_a_fraction
199
+ incorrect_syntax = true
200
+ break
201
+ end
202
+
203
+ last_char_is_a_closed_bracket = false
204
+ operator_awaiting_an_argument = true
205
+ elsif char != ' '
206
+ incorrect_syntax = true
207
+ break
208
+ end
209
+ index += 1
210
+ end
211
+
212
+ if operator_awaiting_an_argument || inside_of_a_fraction
213
+ incorrect_syntax = true
214
+ end
215
+
216
+ !incorrect_syntax
217
+ end
218
+
219
+ private
220
+
221
+ def calculate_rank(current_rank, operator)
222
+ case operator
223
+ when '*'
224
+ current_rank + 1
225
+ when '/'
226
+ current_rank + 1
227
+ when '^'
228
+ current_rank + 2
229
+ else
230
+ current_rank
231
+ end
232
+ end
233
+
234
+ def char_is_an_operator(char)
235
+ %w[+ - * / ^].include? char
236
+ end
237
+
238
+ def find_operator_with_left(operators, fraction)
239
+ counter = 0
240
+ operators.each do |op|
241
+ return counter if op.to_left == fraction && op.not_executed?
242
+
243
+ counter += 1
244
+ end
245
+
246
+ -1
247
+ end
248
+ end
249
+ end
250
+ end