functio 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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