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