save_the_month 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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: []