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.
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -0,0 +1,6 @@
1
+ require_relative './expected_balance'
2
+ require_relative './charge_dsl'
3
+ require_relative './payment_dsl'
4
+ require_relative './recipe_dsl'
5
+ require_relative './query_dsl'
6
+ require_relative './reader_dsl'
@@ -0,0 +1,3 @@
1
+ module SaveTheMonth
2
+ VERSION = "0.0.1"
3
+ end
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: []