functio 0.1.0

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.
Files changed (48) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +3 -0
  3. data/CHANGELOG.md +9 -0
  4. data/COPYING +674 -0
  5. data/Gemfile +16 -0
  6. data/Gemfile.lock +79 -0
  7. data/README.md +109 -0
  8. data/Rakefile +47 -0
  9. data/bin/fn +28 -0
  10. data/features/expression_evaluation.feature +58 -0
  11. data/features/function_creation.feature +74 -0
  12. data/features/function_deletion.feature +37 -0
  13. data/features/function_list.feature +35 -0
  14. data/features/function_use.feature +56 -0
  15. data/features/help_option.feature +13 -0
  16. data/features/step_definitions/steps.rb +36 -0
  17. data/features/support/env.rb +41 -0
  18. data/features/support/functio_world.rb +45 -0
  19. data/features/version_option.feature +19 -0
  20. data/functio.gemspec +43 -0
  21. data/lib/functio.rb +24 -0
  22. data/lib/functio/data_storage.rb +90 -0
  23. data/lib/functio/errors.rb +47 -0
  24. data/lib/functio/expression.rb +61 -0
  25. data/lib/functio/formatted_num.rb +39 -0
  26. data/lib/functio/functio_cli.rb +111 -0
  27. data/lib/functio/function.rb +104 -0
  28. data/lib/functio/function_repository.rb +73 -0
  29. data/lib/functio/version.rb +23 -0
  30. data/test/doubles/expression_double.rb +33 -0
  31. data/test/doubles/function_double.rb +34 -0
  32. data/test/doubles/storage_double.rb +36 -0
  33. data/test/doubles/test_expression_double.rb +30 -0
  34. data/test/doubles/test_function_double.rb +30 -0
  35. data/test/doubles/test_storage_double.rb +30 -0
  36. data/test/expression_interface_test.rb +30 -0
  37. data/test/interface_test_helper.rb +25 -0
  38. data/test/license_test_helper.rb +49 -0
  39. data/test/storable_interface_test.rb +30 -0
  40. data/test/storage_interface_test.rb +30 -0
  41. data/test/test_data_storage.rb +127 -0
  42. data/test/test_expression.rb +89 -0
  43. data/test/test_formatted_num.rb +56 -0
  44. data/test/test_function.rb +142 -0
  45. data/test/test_function_repository.rb +97 -0
  46. data/test/test_helper.rb +22 -0
  47. data/test/test_licenses_compatibility.rb +29 -0
  48. metadata +140 -0
@@ -0,0 +1,35 @@
1
+ Feature: Function list
2
+ In order to know what functions are available
3
+ As a User
4
+ I want to list my functions
5
+
6
+ Scenario: No functions available
7
+ Given I have no functions
8
+ When I successfully run `fn list`
9
+ Then the output should not contain anything
10
+
11
+ Scenario: One function created
12
+ Given I have the function:
13
+ | name | definition |
14
+ | product | multiplier * multiplicand |
15
+ When I run `fn list`
16
+ Then it should pass with:
17
+ """
18
+ product <multiplier> <multiplicand>
19
+ """
20
+
21
+ Scenario: More functions available
22
+ Given I have the functions:
23
+ | name | definition |
24
+ | sum | augend + addend |
25
+ | difference | minuend - subtrahend |
26
+ | product | multiplier * multiplicand |
27
+ | quotient | dividend / divisor |
28
+ When I run `fn list`
29
+ Then it should pass with:
30
+ """
31
+ sum <augend> <addend>
32
+ difference <minuend> <subtrahend>
33
+ product <multiplier> <multiplicand>
34
+ quotient <dividend> <divisor>
35
+ """
@@ -0,0 +1,56 @@
1
+ Feature: Function use
2
+ In order to do my recurrent calculations quickly
3
+ As a User
4
+ I want to use previously created functions
5
+
6
+ Scenario Outline: Successful use of an available function
7
+ Given I have the function:
8
+ | name | definition |
9
+ | add | a + b |
10
+ When I run `fn use add <a> <b>`
11
+ Then it should pass with:
12
+ """
13
+ <result>
14
+ """
15
+ Examples:
16
+ | a | b | result |
17
+ | 1 | 2 | 3 |
18
+ | -1 | 2 | 1 |
19
+ | 0 | 0 | 0 |
20
+ | 3 | -1 | 2 |
21
+ | 3 | 2.5 | 5.5 |
22
+ | 40.5 | 1.5 | 42 |
23
+
24
+ Scenario Outline: Wrong number of function arguments
25
+ Given I have the function:
26
+ | name | definition |
27
+ | add | a + b |
28
+ When I run `fn use add <args>`
29
+ Then it should fail with:
30
+ """
31
+ Error: no value provided for some parameters
32
+ """
33
+ Examples:
34
+ | args |
35
+ | |
36
+ | 1 |
37
+
38
+ Scenario: Inexistent function
39
+ Given I have the function:
40
+ | name | definition |
41
+ | add | a + b |
42
+ When I run `fn use subtract 2 1`
43
+ Then it should fail with:
44
+ """
45
+ Error: function 'subtract' doesn't exist
46
+ """
47
+
48
+ Scenario: Runtime function calculation error
49
+ Given I have the function:
50
+ | name | definition |
51
+ | divide | a / b |
52
+ When I run `fn use divide 1 0`
53
+ Then it should fail with:
54
+ """
55
+ Error: division by zero
56
+ """
@@ -0,0 +1,13 @@
1
+ Feature: Help option
2
+ In order to learn how to use Functio
3
+ As a User
4
+ I want a help option that shows Functio usage
5
+
6
+ Scenario Outline: Run with help option
7
+ When I successfully run `<command>`
8
+ Then the output should contain "Functio commands"
9
+ Examples:
10
+ | command |
11
+ | fn |
12
+ | fn --help |
13
+ | fn help |
@@ -0,0 +1,36 @@
1
+ #--
2
+ # Copyright (C) 2016 Cassiano Rocha Kuplich
3
+ #
4
+ # This file is part of Functio.
5
+ #
6
+ # Functio is free software: you can redistribute it and/or modify
7
+ # it under the terms of the GNU General Public License as published by
8
+ # the Free Software Foundation, either version 3 of the License, or
9
+ # (at your option) any later version.
10
+ #
11
+ # Functio is distributed in the hope that it will be useful,
12
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ # GNU General Public License for more details.
15
+ #
16
+ # You should have received a copy of the GNU General Public License
17
+ # along with Functio. If not, see <http://www.gnu.org/licenses/>.
18
+ #++
19
+
20
+ Given(/^I have no functions$/) do
21
+ FileUtils.remove_dir(data_dir, true)
22
+ end
23
+
24
+ Given(/^I have the functions?:$/) do |table|
25
+ FileUtils.remove_dir(data_dir, true)
26
+ table.symbolic_hashes.each do |function_args|
27
+ function_repo.add(Function.build(function_args))
28
+ end
29
+ end
30
+
31
+ Then(/^the following functions? should be available:$/) do |table|
32
+ functions = table.symbolic_hashes.map do |function_args|
33
+ Function.build(function_args)
34
+ end
35
+ assert_equal(functions, function_repo.all)
36
+ end
@@ -0,0 +1,41 @@
1
+ #--
2
+ # Copyright (C) 2016 Cassiano Rocha Kuplich
3
+ #
4
+ # This file is part of Functio.
5
+ #
6
+ # Functio is free software: you can redistribute it and/or modify
7
+ # it under the terms of the GNU General Public License as published by
8
+ # the Free Software Foundation, either version 3 of the License, or
9
+ # (at your option) any later version.
10
+ #
11
+ # Functio is distributed in the hope that it will be useful,
12
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ # GNU General Public License for more details.
15
+ #
16
+ # You should have received a copy of the GNU General Public License
17
+ # along with Functio. If not, see <http://www.gnu.org/licenses/>.
18
+ #++
19
+
20
+ require 'aruba/cucumber'
21
+ require 'fileutils'
22
+ require 'functio/function'
23
+
24
+ include Functio
25
+
26
+ # Configure Aruba to set $HOME environment variable to ./tmp/aruba
27
+ Aruba.configure do |config|
28
+ config.home_directory = File.join(config.root_directory,
29
+ config.working_directory)
30
+ end
31
+
32
+ # ENV['HOME'] for Cucumber steps must be set too because Cucumber steps runs in
33
+ # another process.
34
+ Before do
35
+ @real_home = ENV['HOME']
36
+ ENV['HOME'] = Aruba.config.home_directory
37
+ end
38
+
39
+ After do
40
+ ENV['HOME'] = @real_home
41
+ end
@@ -0,0 +1,45 @@
1
+ #--
2
+ # Copyright (C) 2016 Cassiano Rocha Kuplich
3
+ #
4
+ # This file is part of Functio.
5
+ #
6
+ # Functio is free software: you can redistribute it and/or modify
7
+ # it under the terms of the GNU General Public License as published by
8
+ # the Free Software Foundation, either version 3 of the License, or
9
+ # (at your option) any later version.
10
+ #
11
+ # Functio is distributed in the hope that it will be useful,
12
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ # GNU General Public License for more details.
15
+ #
16
+ # You should have received a copy of the GNU General Public License
17
+ # along with Functio. If not, see <http://www.gnu.org/licenses/>.
18
+ #++
19
+
20
+ require 'minitest/spec'
21
+ require 'functio/function_repository'
22
+
23
+ # Custom Cucumber World with Minitest assertions and Functio objects.
24
+ class FunctioWorld
25
+ include Minitest::Assertions
26
+ include Functio
27
+
28
+ attr_accessor :assertions # :nodoc:
29
+
30
+ def initialize # :nodoc:
31
+ self.assertions = 0
32
+ end
33
+
34
+ def data_dir # :nodoc:
35
+ function_repo.storage.data_dir
36
+ end
37
+
38
+ def function_repo # :nodoc:
39
+ @function_repo ||= FunctionRepository.new
40
+ end
41
+ end
42
+
43
+ World do
44
+ FunctioWorld.new
45
+ end
@@ -0,0 +1,19 @@
1
+ Feature: Version option
2
+ In order to know the current version of Functio
3
+ As a User
4
+ I want an option to show current Functio version
5
+
6
+ Scenario Outline: Run with version option
7
+ When I successfully run `<command>`
8
+ Then the output should match:
9
+ """
10
+ Functio \d+\.\d+\.\d+
11
+ Copyright \(C\) 2016 Cassiano Rocha Kuplich
12
+ License GPLv3\+: GNU GPL version 3 or later \<http://gnu.org/licenses/gpl\.html\>\.
13
+ This is free software: you are free to change and redistribute it\.
14
+ There is NO WARRANTY, to the extent permitted by law\.
15
+ """
16
+ Examples:
17
+ | command |
18
+ | fn --version |
19
+ | fn version |
@@ -0,0 +1,43 @@
1
+ #--
2
+ # Copyright (C) 2016 Cassiano Rocha Kuplich
3
+ #
4
+ # This file is part of Functio.
5
+ #
6
+ # Functio is free software: you can redistribute it and/or modify
7
+ # it under the terms of the GNU General Public License as published by
8
+ # the Free Software Foundation, either version 3 of the License, or
9
+ # (at your option) any later version.
10
+ #
11
+ # Functio is distributed in the hope that it will be useful,
12
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ # GNU General Public License for more details.
15
+ #
16
+ # You should have received a copy of the GNU General Public License
17
+ # along with Functio. If not, see <http://www.gnu.org/licenses/>.
18
+ #++
19
+
20
+ require_relative 'lib/functio/version'
21
+
22
+ Gem::Specification.new do |s|
23
+ s.name = 'functio'
24
+ s.version = Functio::VERSION
25
+ s.platform = Gem::Platform::RUBY
26
+ s.required_ruby_version = '>= 2.1.9'
27
+ s.summary = 'Turn your recurrent calculations into functions'
28
+ s.description = <<-EOS
29
+ Functio is a calculator that allows you to create and manage functions for your
30
+ recurrent calculations.
31
+ EOS
32
+ s.author = 'Cassiano Kuplich'
33
+ s.email = 'crkuplich@openmailbox.org'
34
+ s.homepage = 'https://gitlab.com/functio/functio'
35
+ s.license = 'GPL-3.0+'
36
+
37
+ s.files = `git ls-files -z`.split("\0")
38
+ s.executables << 'fn'
39
+
40
+ s.add_runtime_dependency 'dentaku', '~> 2.0', '>= 2.0.7'
41
+ s.add_runtime_dependency 'thor', '~> 0.19'
42
+ s.add_development_dependency 'bundler', '~> 1.11'
43
+ end
@@ -0,0 +1,24 @@
1
+ #--
2
+ # Copyright (C) 2016 Cassiano Rocha Kuplich
3
+ #
4
+ # This file is part of Functio.
5
+ #
6
+ # Functio is free software: you can redistribute it and/or modify
7
+ # it under the terms of the GNU General Public License as published by
8
+ # the Free Software Foundation, either version 3 of the License, or
9
+ # (at your option) any later version.
10
+ #
11
+ # Functio is distributed in the hope that it will be useful,
12
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ # GNU General Public License for more details.
15
+ #
16
+ # You should have received a copy of the GNU General Public License
17
+ # along with Functio. If not, see <http://www.gnu.org/licenses/>.
18
+ #++
19
+ # Functio is a calculator that allows you to create and manage functions for
20
+ # your recurrent calculations.
21
+ module Functio
22
+ end
23
+
24
+ require 'functio/functio_cli'
@@ -0,0 +1,90 @@
1
+ #--
2
+ # Copyright (C) 2016 Cassiano Rocha Kuplich
3
+ #
4
+ # This file is part of Functio.
5
+ #
6
+ # Functio is free software: you can redistribute it and/or modify
7
+ # it under the terms of the GNU General Public License as published by
8
+ # the Free Software Foundation, either version 3 of the License, or
9
+ # (at your option) any later version.
10
+ #
11
+ # Functio is distributed in the hope that it will be useful,
12
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ # GNU General Public License for more details.
15
+ #
16
+ # You should have received a copy of the GNU General Public License
17
+ # along with Functio. If not, see <http://www.gnu.org/licenses/>.
18
+ #++
19
+
20
+ require 'csv'
21
+ require 'fileutils'
22
+
23
+ module Functio
24
+ # Manages data storage. DataStorage handles each record data as a Hash, so it
25
+ # expects Hashes when stores data and returns Hashes when retrieves data.
26
+ class DataStorage
27
+ # Directory path of data file.
28
+ attr_reader :data_dir
29
+
30
+ # Path of data file.
31
+ attr_reader :data_file
32
+
33
+ def initialize # :nodoc:
34
+ @data_dir = File.join(ENV['HOME'], '.functio')
35
+ @data_file = File.join(data_dir, 'functions.csv')
36
+ end
37
+
38
+ # Stores a +record+ Hash. The keys of +record+ Hash are the field names and
39
+ # the values are the field values.
40
+ def store(record)
41
+ FileUtils.mkdir_p(data_dir)
42
+ CSV.open(data_file, 'a') do |csv|
43
+ csv.seek(0, IO::SEEK_END)
44
+ csv << record.keys if csv.pos == 0
45
+ csv << record.values
46
+ end
47
+ end
48
+
49
+ # Finds a record that matches exactly the +fields+ Hash passed. The keys of
50
+ # +fields+ Hash are the field names and the values are the field values to
51
+ # match exactly with the record searched for.
52
+ def find(fields)
53
+ found = table.find { |row| row_matches?(row, fields) }
54
+ found.to_h if found
55
+ end
56
+
57
+ # Returns all stored records as an Array of Hashes. Each Hash is a record.
58
+ def all
59
+ table.map(&:to_h)
60
+ end
61
+
62
+ # Deletes a record that matches exactly the +fields+ passed in. See
63
+ # DataStorage#find for +fields+ Hash description. Returns +true+ if the
64
+ # record matching +fields+ is deleted successfully or +false+ otherwise.
65
+ def delete(fields)
66
+ tbl = table
67
+ row_idx = tbl.find_index { |row| row_matches?(row, fields) }
68
+ return false unless row_idx
69
+ tbl.delete(row_idx)
70
+ if tbl.empty?
71
+ FileUtils.remove_dir(data_dir, true)
72
+ else
73
+ File.open(data_file, 'w') { |f| f.write(tbl.to_csv) }
74
+ end
75
+ true
76
+ end
77
+
78
+ private
79
+
80
+ def table
81
+ CSV.table(data_file)
82
+ rescue SystemCallError
83
+ CSV::Table.new([])
84
+ end
85
+
86
+ def row_matches?(row, fields)
87
+ row.fields(*fields.keys) == fields.values
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,47 @@
1
+ #--
2
+ # Copyright (C) 2016 Cassiano Rocha Kuplich
3
+ #
4
+ # This file is part of Functio.
5
+ #
6
+ # Functio is free software: you can redistribute it and/or modify
7
+ # it under the terms of the GNU General Public License as published by
8
+ # the Free Software Foundation, either version 3 of the License, or
9
+ # (at your option) any later version.
10
+ #
11
+ # Functio is distributed in the hope that it will be useful,
12
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ # GNU General Public License for more details.
15
+ #
16
+ # You should have received a copy of the GNU General Public License
17
+ # along with Functio. If not, see <http://www.gnu.org/licenses/>.
18
+ #++
19
+
20
+ module Functio
21
+ # Base exception class for Functio errors.
22
+ class FunctioError < StandardError
23
+ # Original exception.
24
+ attr_reader :original
25
+
26
+ # Constructs a new FunctioError instance passing in a +message+ and
27
+ # optionally the +original+ exception which caused this.
28
+ def initialize(message = nil, original = $ERROR_INFO)
29
+ super(message)
30
+ @original = original
31
+ end
32
+ end
33
+
34
+ # Indicates that a function is invalid.
35
+ class InvalidFunctionError < FunctioError; end
36
+
37
+ # Indicates that an expression is invalid.
38
+ class InvalidExpressionError < FunctioError; end
39
+
40
+ # Indicates a division by zero.
41
+ class DivisionByZeroError < FunctioError
42
+ # Constructs a DivisionByZeroError instance passing in a +message+.
43
+ def initialize(message = 'division by zero')
44
+ super(message)
45
+ end
46
+ end
47
+ end