save_the_month 0.0.1
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/bin/save-the-month +30 -0
- data/lib/charge_dsl.rb +22 -0
- data/lib/expected_balance.rb +92 -0
- data/lib/payment_dsl.rb +22 -0
- data/lib/query_dsl.rb +55 -0
- data/lib/reader_dsl.rb +25 -0
- data/lib/recipe_dsl.rb +36 -0
- data/lib/save_the_month.rb +6 -0
- data/lib/version.rb +3 -0
- metadata +68 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 6e8604f390124f9d37e38123b41f9ec3594ff43e
|
4
|
+
data.tar.gz: 386a89913da11f926df5138c00ed79549202640f
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: b7adfd43753e61ea8fcf396de817133a99fde3a6d8e58e5575bf8228d4e4cc85e70516b3da647645c041cc2ce57db0d553dfc54cad6f77252169431eb1bbe4c2
|
7
|
+
data.tar.gz: d18046cc7eb2d83ffa0095f617eaabe194f3c5a7fab7fa52324df4eeb307ed6e7d90eaf87fba931b93fcab36fd8eadb2ec4ed2ccede8944e6b84b221fb3b7592
|
data/bin/save-the-month
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'save_the_month'
|
4
|
+
|
5
|
+
if ARGV.size > 1
|
6
|
+
|
7
|
+
recipe_file = ARGV[0]
|
8
|
+
|
9
|
+
recipe = File.read(recipe_file)
|
10
|
+
|
11
|
+
recipe_dsl = SaveTheMonth::RecipeDsl.new
|
12
|
+
recipe_dsl.instance_eval(recipe)
|
13
|
+
|
14
|
+
query_file = ARGV[1]
|
15
|
+
|
16
|
+
query = File.read(query_file)
|
17
|
+
|
18
|
+
query_dsl = SaveTheMonth::QueryDsl.new(recipe_dsl.expected_balance)
|
19
|
+
query_dsl.instance_eval(query)
|
20
|
+
|
21
|
+
elsif ARGV.size == 1
|
22
|
+
|
23
|
+
balance_file = ARGV[0]
|
24
|
+
|
25
|
+
recipe = File.read(balance_file)
|
26
|
+
|
27
|
+
reader_dsl = SaveTheMonth::ReaderDsl.new
|
28
|
+
reader_dsl.evaluate_recipe(recipe)
|
29
|
+
|
30
|
+
end
|
data/lib/charge_dsl.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
module SaveTheMonth
|
2
|
+
class ChargeDsl
|
3
|
+
attr_accessor :expected_balance
|
4
|
+
|
5
|
+
def evaluate_recipe(expected_balance, &recipe)
|
6
|
+
self.expected_balance = expected_balance
|
7
|
+
instance_eval(&recipe)
|
8
|
+
end
|
9
|
+
|
10
|
+
def method_missing(meth, *args, &blk)
|
11
|
+
charge_name = meth
|
12
|
+
|
13
|
+
if block_given?
|
14
|
+
expected_balance.add_charge(charge_name, &blk)
|
15
|
+
else
|
16
|
+
amount, options = args[0], args[1]
|
17
|
+
amount_date = Date.parse(options[:at])
|
18
|
+
expected_balance.add_timed_charge(charge_name, amount, amount_date)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
require 'delegate'
|
2
|
+
|
3
|
+
module SaveTheMonth
|
4
|
+
class Movement < Struct.new(:type, :name, :amount)
|
5
|
+
def can_perform?(given_date, initial_date)
|
6
|
+
true
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
class DailyRestrictedMovement < SimpleDelegator
|
11
|
+
attr_accessor :date
|
12
|
+
|
13
|
+
def can_perform?(given_date, initial_date)
|
14
|
+
given_date == date
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
class PeriodicalMovement < SimpleDelegator
|
19
|
+
attr_accessor :can_perform_strategy
|
20
|
+
|
21
|
+
def can_perform?(given_date, initial_date)
|
22
|
+
can_perform_strategy.call(given_date, initial_date)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
PeriodicalStrategy = Struct.new(:amount, :can_perform)
|
27
|
+
|
28
|
+
class PaymentPeriodicalStrategies
|
29
|
+
def daily(amount)
|
30
|
+
# everyday this should be substracted or added
|
31
|
+
can_perform = ->(given_date, initial_date){ true }
|
32
|
+
PeriodicalStrategy.new(amount, can_perform)
|
33
|
+
end
|
34
|
+
|
35
|
+
def weekly(amount)
|
36
|
+
can_perform = ->(given_date, initial_date) do
|
37
|
+
# every week. I can only happen if today
|
38
|
+
# is one of the next days: [6, 13, 20 or 27 days after the initial date]
|
39
|
+
week_days = [ initial_date + 6, initial_date + 13, initial_date + 20, initial_date + 27]
|
40
|
+
week_days.include?(given_date)
|
41
|
+
end
|
42
|
+
|
43
|
+
PeriodicalStrategy.new(amount, can_perform)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
class ExpectedBalance
|
48
|
+
attr_accessor :initial_date, :final_date, :initial_amount, :movements, :periodical_strategies
|
49
|
+
|
50
|
+
def initialize
|
51
|
+
self.movements = []
|
52
|
+
self.periodical_strategies = PaymentPeriodicalStrategies.new
|
53
|
+
end
|
54
|
+
|
55
|
+
def add_charge(name, &perform)
|
56
|
+
movements << make_movement(:charge, name, &perform)
|
57
|
+
end
|
58
|
+
|
59
|
+
def add_payment(name, &perform)
|
60
|
+
movements << make_movement(:payment, name, &perform)
|
61
|
+
end
|
62
|
+
|
63
|
+
def add_timed_payment(name, amount, date)
|
64
|
+
movements << make_timed_movement(name, -amount, date)
|
65
|
+
end
|
66
|
+
|
67
|
+
def add_timed_charge(name, amount, date)
|
68
|
+
movements << make_timed_movement(name, amount, date)
|
69
|
+
end
|
70
|
+
|
71
|
+
private
|
72
|
+
|
73
|
+
def make_movement(type, name, &perform)
|
74
|
+
strategy = periodical_strategies.instance_eval(&perform)
|
75
|
+
amount = type == :payment ? -strategy.amount : strategy.amount
|
76
|
+
|
77
|
+
movement = PeriodicalMovement.new(Movement.new(type, name, amount))
|
78
|
+
movement.can_perform_strategy = strategy.can_perform
|
79
|
+
movement
|
80
|
+
end
|
81
|
+
|
82
|
+
def make_timed_movement(name, amount, date)
|
83
|
+
movement = DailyRestrictedMovement.new(Movement.new(kind_for(amount), name, amount))
|
84
|
+
movement.date = date
|
85
|
+
movement
|
86
|
+
end
|
87
|
+
|
88
|
+
def kind_for(amount)
|
89
|
+
amount > 0 ? :charge : :payment
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
data/lib/payment_dsl.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
module SaveTheMonth
|
2
|
+
class PaymentDsl
|
3
|
+
attr_accessor :expected_balance
|
4
|
+
|
5
|
+
def evaluate_recipe(expected_balance, &recipe)
|
6
|
+
self.expected_balance = expected_balance
|
7
|
+
instance_eval(&recipe)
|
8
|
+
end
|
9
|
+
|
10
|
+
def method_missing(meth, *args, &blk)
|
11
|
+
payment_name = meth
|
12
|
+
|
13
|
+
if block_given?
|
14
|
+
expected_balance.add_payment(payment_name, &blk)
|
15
|
+
else
|
16
|
+
amount, options = args[0], args[1]
|
17
|
+
amount_date = Date.parse(options[:at])
|
18
|
+
expected_balance.add_timed_payment(payment_name, amount, amount_date)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
data/lib/query_dsl.rb
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
module SaveTheMonth
|
2
|
+
class ExpectedAmountQuery
|
3
|
+
attr_accessor :balance, :amount
|
4
|
+
|
5
|
+
def initialize(balance)
|
6
|
+
self.balance = balance
|
7
|
+
end
|
8
|
+
|
9
|
+
def at_beginning
|
10
|
+
balance.initial_amount
|
11
|
+
end
|
12
|
+
|
13
|
+
def today
|
14
|
+
at_date Date.new
|
15
|
+
end
|
16
|
+
|
17
|
+
def at_end
|
18
|
+
at_date balance.final_date
|
19
|
+
end
|
20
|
+
|
21
|
+
def at_date(boundary_date)
|
22
|
+
self.amount = balance.initial_amount
|
23
|
+
|
24
|
+
(balance.initial_date..boundary_date).each do |date|
|
25
|
+
update_with_day(date)
|
26
|
+
end
|
27
|
+
|
28
|
+
self.amount
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def update_with_day(date)
|
34
|
+
self.amount = balance.movements.inject(self.amount) do |amount, movement|
|
35
|
+
if movement.can_perform?(date, balance.initial_date)
|
36
|
+
amount + movement.amount
|
37
|
+
else
|
38
|
+
amount
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
class QueryDsl
|
45
|
+
attr_accessor :balance
|
46
|
+
|
47
|
+
def initialize(balance)
|
48
|
+
self.balance = balance
|
49
|
+
end
|
50
|
+
|
51
|
+
def expected_amount
|
52
|
+
ExpectedAmountQuery.new(balance)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
data/lib/reader_dsl.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
require_relative './recipe_dsl'
|
2
|
+
require_relative './query_dsl'
|
3
|
+
|
4
|
+
module SaveTheMonth
|
5
|
+
class ReaderDsl
|
6
|
+
attr_accessor :recipe_dsl, :query_dsl
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
self.recipe_dsl = RecipeDsl.new
|
10
|
+
end
|
11
|
+
|
12
|
+
def evaluate_recipe(recipe_in_text)
|
13
|
+
instance_eval(recipe_in_text)
|
14
|
+
end
|
15
|
+
|
16
|
+
def recipe(&blk)
|
17
|
+
self.recipe_dsl.instance_eval(&blk)
|
18
|
+
end
|
19
|
+
|
20
|
+
def query(&blk)
|
21
|
+
self.query_dsl = SaveTheMonth::QueryDsl.new(recipe_dsl.expected_balance)
|
22
|
+
self.query_dsl.instance_eval(&blk)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
data/lib/recipe_dsl.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'date'
|
2
|
+
require_relative './expected_balance'
|
3
|
+
require_relative './payment_dsl'
|
4
|
+
require_relative './charge_dsl'
|
5
|
+
|
6
|
+
module SaveTheMonth
|
7
|
+
class RecipeDsl
|
8
|
+
attr_accessor :expected_balance, :payment_dsl, :charge_dsl
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
self.expected_balance = ExpectedBalance.new
|
12
|
+
self.payment_dsl = PaymentDsl.new
|
13
|
+
self.charge_dsl = ChargeDsl.new
|
14
|
+
end
|
15
|
+
|
16
|
+
def initial_date(date)
|
17
|
+
expected_balance.initial_date = Date.parse(date)
|
18
|
+
end
|
19
|
+
|
20
|
+
def final_date(date)
|
21
|
+
expected_balance.final_date = Date.parse(date)
|
22
|
+
end
|
23
|
+
|
24
|
+
def initial_amount(amount)
|
25
|
+
expected_balance.initial_amount = amount
|
26
|
+
end
|
27
|
+
|
28
|
+
def to_pay(&block)
|
29
|
+
payment_dsl.evaluate_recipe(expected_balance, &block)
|
30
|
+
end
|
31
|
+
|
32
|
+
def to_charge(&block)
|
33
|
+
charge_dsl.evaluate_recipe(expected_balance, &block)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
data/lib/version.rb
ADDED
metadata
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: save_the_month
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Julio García
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2010-04-28 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rspec
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
description: Dsl to set expectations of the incomings and outcoming of this month's
|
28
|
+
salary
|
29
|
+
email: julioggonz@gmail.com
|
30
|
+
executables:
|
31
|
+
- save-the-month
|
32
|
+
extensions: []
|
33
|
+
extra_rdoc_files: []
|
34
|
+
files:
|
35
|
+
- lib/charge_dsl.rb
|
36
|
+
- lib/expected_balance.rb
|
37
|
+
- lib/payment_dsl.rb
|
38
|
+
- lib/query_dsl.rb
|
39
|
+
- lib/reader_dsl.rb
|
40
|
+
- lib/recipe_dsl.rb
|
41
|
+
- lib/save_the_month.rb
|
42
|
+
- lib/version.rb
|
43
|
+
- bin/save-the-month
|
44
|
+
homepage: https://github.com/juliogarciag/save_the_month
|
45
|
+
licenses:
|
46
|
+
- MIT
|
47
|
+
metadata: {}
|
48
|
+
post_install_message:
|
49
|
+
rdoc_options: []
|
50
|
+
require_paths:
|
51
|
+
- lib
|
52
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
53
|
+
requirements:
|
54
|
+
- - ">="
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: '0'
|
57
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
requirements: []
|
63
|
+
rubyforge_project:
|
64
|
+
rubygems_version: 2.1.3
|
65
|
+
signing_key:
|
66
|
+
specification_version: 4
|
67
|
+
summary: Dsl to set expectations of the incomings and outcoming of this month's salary
|
68
|
+
test_files: []
|