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.
- checksums.yaml +7 -0
- data/.gitignore +3 -0
- data/CHANGELOG.md +9 -0
- data/COPYING +674 -0
- data/Gemfile +16 -0
- data/Gemfile.lock +79 -0
- data/README.md +109 -0
- data/Rakefile +47 -0
- data/bin/fn +28 -0
- data/features/expression_evaluation.feature +58 -0
- data/features/function_creation.feature +74 -0
- data/features/function_deletion.feature +37 -0
- data/features/function_list.feature +35 -0
- data/features/function_use.feature +56 -0
- data/features/help_option.feature +13 -0
- data/features/step_definitions/steps.rb +36 -0
- data/features/support/env.rb +41 -0
- data/features/support/functio_world.rb +45 -0
- data/features/version_option.feature +19 -0
- data/functio.gemspec +43 -0
- data/lib/functio.rb +24 -0
- data/lib/functio/data_storage.rb +90 -0
- data/lib/functio/errors.rb +47 -0
- data/lib/functio/expression.rb +61 -0
- data/lib/functio/formatted_num.rb +39 -0
- data/lib/functio/functio_cli.rb +111 -0
- data/lib/functio/function.rb +104 -0
- data/lib/functio/function_repository.rb +73 -0
- data/lib/functio/version.rb +23 -0
- data/test/doubles/expression_double.rb +33 -0
- data/test/doubles/function_double.rb +34 -0
- data/test/doubles/storage_double.rb +36 -0
- data/test/doubles/test_expression_double.rb +30 -0
- data/test/doubles/test_function_double.rb +30 -0
- data/test/doubles/test_storage_double.rb +30 -0
- data/test/expression_interface_test.rb +30 -0
- data/test/interface_test_helper.rb +25 -0
- data/test/license_test_helper.rb +49 -0
- data/test/storable_interface_test.rb +30 -0
- data/test/storage_interface_test.rb +30 -0
- data/test/test_data_storage.rb +127 -0
- data/test/test_expression.rb +89 -0
- data/test/test_formatted_num.rb +56 -0
- data/test/test_function.rb +142 -0
- data/test/test_function_repository.rb +97 -0
- data/test/test_helper.rb +22 -0
- data/test/test_licenses_compatibility.rb +29 -0
- 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 |
|
data/functio.gemspec
ADDED
@@ -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
|
data/lib/functio.rb
ADDED
@@ -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
|