money_tracking 0.99.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +16 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +8 -0
  5. data/Gemfile +10 -0
  6. data/LICENSE.txt +22 -0
  7. data/README.md +61 -0
  8. data/Rakefile +2 -0
  9. data/bin/money +6 -0
  10. data/lib/money_tracking.rb +6 -0
  11. data/lib/money_tracking/cli.rb +88 -0
  12. data/lib/money_tracking/cli/commands.rb +7 -0
  13. data/lib/money_tracking/cli/create_command.rb +21 -0
  14. data/lib/money_tracking/cli/delete_command.rb +15 -0
  15. data/lib/money_tracking/cli/list_command.rb +16 -0
  16. data/lib/money_tracking/cli/runner.rb +54 -0
  17. data/lib/money_tracking/cli/update_command.rb +33 -0
  18. data/lib/money_tracking/cli/views.rb +15 -0
  19. data/lib/money_tracking/cli/views/empty.rb +11 -0
  20. data/lib/money_tracking/cli/views/expense_created.rb +11 -0
  21. data/lib/money_tracking/cli/views/expense_deleted.rb +15 -0
  22. data/lib/money_tracking/cli/views/expense_item.rb +34 -0
  23. data/lib/money_tracking/cli/views/expense_list.rb +11 -0
  24. data/lib/money_tracking/cli/views/expense_not_found.rb +15 -0
  25. data/lib/money_tracking/cli/views/expense_not_updated.rb +19 -0
  26. data/lib/money_tracking/cli/views/expense_updated.rb +15 -0
  27. data/lib/money_tracking/data_store/file_store.rb +81 -0
  28. data/lib/money_tracking/data_store/protocol.rb +20 -0
  29. data/lib/money_tracking/domain.rb +12 -0
  30. data/lib/money_tracking/domain/expense.rb +92 -0
  31. data/lib/money_tracking/domain/expense_factory.rb +15 -0
  32. data/lib/money_tracking/domain/expense_finder.rb +13 -0
  33. data/lib/money_tracking/version.rb +3 -0
  34. data/money_tracking.gemspec +25 -0
  35. data/spec/aruba_helper.rb +31 -0
  36. data/spec/integration/cli_spec.rb +129 -0
  37. data/spec/money_tracking/cli/create_command_spec.rb +38 -0
  38. data/spec/money_tracking/cli/delete_command_spec.rb +44 -0
  39. data/spec/money_tracking/cli/list_command_spec.rb +34 -0
  40. data/spec/money_tracking/cli/update_command_spec.rb +92 -0
  41. data/spec/money_tracking/cli/views/expense_item_spec.rb +60 -0
  42. data/spec/money_tracking/cli/views/expense_list_spec.rb +40 -0
  43. data/spec/money_tracking/data_store/acts_as_a_data_store.rb +144 -0
  44. data/spec/money_tracking/data_store/file_store_spec.rb +16 -0
  45. data/spec/money_tracking/domain/expense_factory_spec.rb +58 -0
  46. data/spec/money_tracking/domain/expense_finder_spec.rb +59 -0
  47. data/spec/money_tracking/domain/expense_spec.rb +125 -0
  48. data/spec/spec_helper.rb +32 -0
  49. metadata +148 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 67cefce6f95c9bfe68d90b956571cb83ab1234b0
4
+ data.tar.gz: 0f84283110e2903c65a8a959015f816ed014a8d1
5
+ SHA512:
6
+ metadata.gz: e57d828e36a7c18bb11a6f4d3bdedcc3f081745168497016ec88fae88a9aa79984d0bc1e24930561f82771f346081d327784300fd4fa0a90cb79f2279dd298e4
7
+ data.tar.gz: 359885f0dc1f01afb8bcc218db5ee9809367c24ca29bdc76d2972fabc028ccb3f0c1748c94a367c8717983566a797a6be19aa4e251178c63b0bf35f4a17c7acc
@@ -0,0 +1,16 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
15
+ created_some
16
+ changed_amount
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --require spec_helper
@@ -0,0 +1,8 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.0.0
4
+ - 2.1
5
+ - 2.2
6
+
7
+ script: bundle exec rspec
8
+ bundler_args: --without development
data/Gemfile ADDED
@@ -0,0 +1,10 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in money_tracking.gemspec
4
+ gemspec
5
+
6
+ group :test do
7
+ gem "rspec"
8
+ gem "aruba"
9
+ gem "timecop"
10
+ end
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2015 Alexey Fedorov
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,61 @@
1
+ # MoneyTracking
2
+
3
+ CLI tool for tracking your expenses.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'money_tracking'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install money_tracking
20
+
21
+ ## Usage
22
+
23
+ ```
24
+ $ money expenses list
25
+ Empty.
26
+
27
+ $ money expenses create 37.9 euro food
28
+ Created new expense with id 7dt0ibnv.
29
+
30
+ $ money expenses create 25 euro internet landline
31
+ Created new expense with id 2pa44pry.
32
+
33
+ $ money expenses list
34
+ 2pa44pry - 2015-04-17 18:17:37: 25.00 euro [internet landline]
35
+ 7dt0ibnv - 2015-04-17 18:24:21: 37.90 euro [food]
36
+
37
+ $ money expenses update 7dt0ibnv --amount 37.95
38
+ Updated expense 7dt0ibnv.
39
+
40
+ $ money expenses list
41
+ 2pa44pry - 2015-04-17 18:17:37: 25.00 euro [internet landline]
42
+ 7dt0ibnv - 2015-04-17 18:24:21: 37.95 euro [food]
43
+
44
+ $ money expenses delete 2pa44pry
45
+ Deleted expense 2pa44pry.
46
+
47
+ $ money expenses list
48
+ 7dt0ibnv - 2015-04-17 18:24:21: 37.95 euro [food]
49
+ ```
50
+
51
+ ## Contributing
52
+
53
+ 1. Fork it ( https://github.com/waterlink/money_tracking/fork )
54
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
55
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
56
+ 4. Push to the branch (`git push origin my-new-feature`)
57
+ 5. Create a new Pull Request
58
+
59
+ ## Contributors
60
+
61
+ - [waterlink](https://github.com/waterlink) Oleksii Fedorov - creator, maintainer
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $:.unshift(File.expand_path(File.join(__FILE__, "..", "..", "lib")))
4
+ require "money_tracking/cli/runner"
5
+
6
+ MoneyTracking::Cli::Runner.new(ARGV).execute!
@@ -0,0 +1,6 @@
1
+ require "money_tracking/version"
2
+ require "money_tracking/domain"
3
+ require "money_tracking/data_store/protocol"
4
+
5
+ module MoneyTracking
6
+ end
@@ -0,0 +1,88 @@
1
+ require "money_tracking"
2
+ require "money_tracking/cli/views"
3
+ require "money_tracking/cli/commands"
4
+ require "money_tracking/data_store/file_store"
5
+
6
+ require "thor"
7
+
8
+ module MoneyTracking
9
+ module Cli
10
+ class Error < StandardError
11
+ def initialize(view)
12
+ @view = view
13
+ end
14
+
15
+ def render
16
+ puts view.to_s
17
+ end
18
+
19
+ private
20
+
21
+ attr_reader :view
22
+ end
23
+
24
+ class Expenses < Thor
25
+ desc "list", "List all expenses"
26
+ def list
27
+ render ListCommand.new(expense_finder).call
28
+ end
29
+
30
+ desc "create AMOUNT CURRENCY TAGS", "Creates an expense"
31
+ def create(amount, currency, *tags)
32
+ render CreateCommand.new(expense_factory, amount, currency, tags).call
33
+ end
34
+
35
+ desc "update EXPENSE_ID", "Updates an expense"
36
+ method_option :amount, type: :numeric
37
+ method_option :currency
38
+ method_option :add_tags, type: :array
39
+ method_option :rm_tags, type: :array
40
+ def update(expense_id)
41
+ render UpdateCommand.new(
42
+ expense_finder,
43
+ expense_id,
44
+ options.amount,
45
+ options.currency,
46
+ options.add_tags,
47
+ options.rm_tags,
48
+ ).call
49
+ end
50
+
51
+ desc "delete EXPENSE_ID", "Deletes an expense"
52
+ def delete(expense_id)
53
+ render DeleteCommand.new(expense_finder, expense_id).call
54
+ end
55
+
56
+ private
57
+
58
+ def expense_factory
59
+ Domain::ExpenseFactory.new(store)
60
+ end
61
+
62
+ def expense_finder
63
+ Domain::ExpenseFinder.new(store, expense_factory)
64
+ end
65
+
66
+ def store
67
+ @_store ||= DataStore::FileStore.new(file_store_dir)
68
+ end
69
+
70
+ def file_store_dir
71
+ "#{user_home}/.money/expenses"
72
+ end
73
+
74
+ def user_home
75
+ ENV.fetch("TEST_HOME", ENV["HOME"])
76
+ end
77
+
78
+ def render(view)
79
+ puts view.to_s
80
+ end
81
+ end
82
+
83
+ class App < Thor
84
+ desc "expenses", "Work with expenses, use money help expenses to get list of subcommands"
85
+ subcommand "expenses", Expenses
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,7 @@
1
+ COMMANDS = %w[
2
+ list create update delete
3
+ ]
4
+
5
+ COMMANDS.each do |command|
6
+ require "money_tracking/cli/#{command}_command"
7
+ end
@@ -0,0 +1,21 @@
1
+ module MoneyTracking
2
+ module Cli
3
+ class CreateCommand < Struct.new(:expense_factory, :amount, :currency, :tags)
4
+ def call
5
+ expense_factory
6
+ .create(raw_expense)
7
+ .build_view(Views::ExpenseCreated)
8
+ end
9
+
10
+ private
11
+
12
+ def raw_expense
13
+ {
14
+ amount: amount.to_f,
15
+ currency: currency,
16
+ tags: tags,
17
+ }
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,15 @@
1
+ module MoneyTracking
2
+ module Cli
3
+ class DeleteCommand < Struct.new(:expense_finder, :expense_id)
4
+ def call
5
+ expense.delete.build_view(Views::ExpenseDeleted)
6
+ end
7
+
8
+ private
9
+
10
+ def expense
11
+ expense_finder.read(expense_id)
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,16 @@
1
+ module MoneyTracking
2
+ module Cli
3
+ class ListCommand < Struct.new(:expense_finder)
4
+ def call
5
+ return Views::Empty.new if expenses.empty?
6
+ Views::ExpenseList.new(expenses, Views::ExpenseItem)
7
+ end
8
+
9
+ private
10
+
11
+ def expenses
12
+ @_expenses ||= expense_finder.list
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,54 @@
1
+ require "money_tracking/cli"
2
+
3
+ module MoneyTracking
4
+ module Cli
5
+ class Runner
6
+ def initialize(argv, stdin = STDIN, stdout = STDOUT, stderr = STDERR, kernel = Kernel)
7
+ @argv, @stdin, @stdout, @stderr, @kernel = argv, stdin, stdout, stderr, kernel
8
+ end
9
+
10
+ def execute!
11
+ kernel.exit(run_cli { App.start(argv) })
12
+ end
13
+
14
+ private
15
+
16
+ attr_reader :argv, :stderr, :stdin, :stdout, :kernel
17
+
18
+ def setup_streams
19
+ $stderr = stderr
20
+ $stdin = stdin
21
+ $stdout = stdout
22
+ end
23
+
24
+ def reset_streams
25
+ $stderr = STDERR
26
+ $stdin = STDIN
27
+ $stdout = STDOUT
28
+ end
29
+
30
+ def run_cli
31
+ setup_streams
32
+ yield
33
+ 0
34
+
35
+ rescue Cli::Error => e
36
+ e.render
37
+ 1
38
+
39
+ rescue StandardError => e
40
+ b = e.backtrace
41
+ stderr.puts("#{b.shift}: #{e.message} (#{e.class})")
42
+ stderr.puts(b.map{|s| "\tfrom #{s}"}.join("\n"))
43
+ 1
44
+
45
+ rescue SystemExit => e
46
+ e.status
47
+
48
+ ensure
49
+ reset_streams
50
+
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,33 @@
1
+ module MoneyTracking
2
+ module Cli
3
+ class UpdateCommand < Struct.new(:expense_finder, :expense_id, :amount, :currency, :add_tags, :rm_tags)
4
+ def call
5
+ expense
6
+ .update(
7
+ amount: amount,
8
+ currency: currency,
9
+ add_tags: add_tags,
10
+ rm_tags: rm_tags,
11
+ ).build_view(view_factory)
12
+ end
13
+
14
+ private
15
+
16
+ def expense
17
+ @_expense ||= expense_finder.read(expense_id)
18
+ end
19
+
20
+ def view_factory
21
+ return Views::ExpenseNotUpdated unless updating?
22
+ Views::ExpenseUpdated
23
+ end
24
+
25
+ def updating?
26
+ [amount,
27
+ currency,
28
+ add_tags && !add_tags.empty?,
29
+ rm_tags && !rm_tags.empty?].any?
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,15 @@
1
+ VIEWS = %w[
2
+ empty expense_list expense_item expense_created
3
+ expense_updated expense_deleted expense_not_found
4
+ expense_not_updated
5
+ ]
6
+
7
+ module MoneyTracking
8
+ module Cli
9
+ module Views
10
+ VIEWS.each do |view|
11
+ require "money_tracking/cli/views/#{view}"
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,11 @@
1
+ module MoneyTracking
2
+ module Cli
3
+ module Views
4
+ class Empty
5
+ def to_s
6
+ "Empty."
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ module MoneyTracking
2
+ module Cli
3
+ module Views
4
+ class ExpenseCreated < Struct.new(:expense)
5
+ def to_s
6
+ "Created new expense with id #{expense[:id]}."
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,15 @@
1
+ module MoneyTracking
2
+ module Cli
3
+ module Views
4
+ class ExpenseDeleted < Struct.new(:expense)
5
+ def self.not_found
6
+ ExpenseNotFound
7
+ end
8
+
9
+ def to_s
10
+ "Deleted expense #{expense[:id]}."
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end