ldgr 0.1.8 → 0.1.9

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: dd1b9f7d89658b02753509fe2c2b768627ad4fa8
4
- data.tar.gz: 5978628789242f582e8830f30f24fcca9e59d3e2
3
+ metadata.gz: 5a5adf1070c9805e0c5f9b7795a5053e68605190
4
+ data.tar.gz: 17af8d0b4619d9c529d8417d063b7a9e791a5bd3
5
5
  SHA512:
6
- metadata.gz: e255ab170b8b1ef33fd2ab0639befe62455ab602651b7838b9eb00fb8477343e2b04c49c677ba8693805eee80955df478f537a50b52b2abdde6b808268d8a771
7
- data.tar.gz: 5d75bc6a48e72a46b1794034357c35e9bf01cab8f9aa5851b901f709d90c306f34938a86b1961ea86d92371e667202d4a06c34fe384023a3a48dfca68022dd7b
6
+ metadata.gz: e381ee9ba9d38eb313165aabc7bbbf2cedf3413b5b9af52f85be3634ffa4079d7e3f7e96d02ae7373b4db7fbb049c892760052b93cb34bfd183f92509b03d8f8
7
+ data.tar.gz: d7764d3aa17416fdd1400067457c32fe2e0992e07c64e34694f75bf64791849494558f9bc09dd502b5384d63d71ffbff2185fb99310eb51bb5f88cb8db93b149
data/.gitignore CHANGED
@@ -1,3 +1,4 @@
1
+ CODE_OF_CONDUCT.md
1
2
  /.bundle/
2
3
  /.yardoc
3
4
  /Gemfile.lock
data/bin/ldgr CHANGED
@@ -2,4 +2,5 @@
2
2
 
3
3
  require 'ldgr'
4
4
 
5
- Ldgr::Parser.parse
5
+ parser = Ldgr::Parser.new
6
+ parser.parse
data/lib/ldgr/parser.rb CHANGED
@@ -10,19 +10,82 @@ require 'fileutils'
10
10
  require 'yaml'
11
11
 
12
12
  module Ldgr
13
+ # Parses configuration options.
14
+ #
15
+ #
16
+ # Examples
17
+ #
18
+ # Ldgr::Parser.parse
19
+ # # => some file action
20
+ #
21
+ # Returns nothing on success.
13
22
  class Parser
14
23
  FILEBASE = Dir.home + '/.config/ledger/'
15
- FILE = FILEBASE + 'transactions.dat'
16
24
  VERSION = Ldgr::VERSION
17
25
  PROGRAM_NAME = 'ldgr'
18
26
  MATCH = /(?=(\n\d\d\d\d-\d\d-\d\d)(=\d\d\d\d-\d\d-\d\d)*)|\z/
19
27
  OTHER_MATCH = /(?=(\d\d\d\d-\d\d-\d\d)(=\d\d\d\d-\d\d-\d\d)*)/
20
- COMMANDS = %w(add sort tag clear open)
21
- SETUP_FILES = %w(transactions.dat accounts.dat budgets.dat aliases.dat commodities.dat setup.dat ledger.dat ldgr.yaml)
22
- CONFIG_FILE = Pathname(FILEBASE + 'ldgr.yaml')
23
- LDGR_DEFAULTS = { currency: '$', equity: 'Cash' }.to_h
24
28
 
25
- def self.parse
29
+ attr_accessor :transactions_file, :config
30
+
31
+ # Public: Creates a new Parser object
32
+ #
33
+ # config - A hash of config options
34
+ #
35
+ # Examples
36
+ #
37
+ # new(config: {currency: '¥'})
38
+ # # => <ParserObject>
39
+ #
40
+ # Returns a Parser object.
41
+ def initialize(config: {})
42
+ @transactions_file = defaults.fetch(:transactions_file)
43
+ @config = defaults.merge(user_config).merge(config)
44
+ end
45
+
46
+ # Public: User-specified config options
47
+ #
48
+ # Examples
49
+ #
50
+ # user_config
51
+ # # => {all the config options from the user's YAML file}
52
+ #
53
+ # Returns a hash of user-specified config options.
54
+ def user_config
55
+ path = Pathname(FILEBASE + 'ldgr.yaml')
56
+ YAML.load_file(path).to_h
57
+ end
58
+
59
+ # Public: available commands
60
+ #
61
+ # Examples
62
+ #
63
+ # commands
64
+ #
65
+ # Returns an array of command names.
66
+ def commands
67
+ %w(add sort tag clear open)
68
+ end
69
+
70
+ # Public: expected setup files
71
+ #
72
+ # Examples
73
+ #
74
+ # setup_files
75
+ #
76
+ # Returns an array of file names.
77
+ def self.setup_files
78
+ %w(transactions.dat accounts.dat budgets.dat aliases.dat commodities.dat setup.dat ledger.dat ldgr.yaml)
79
+ end
80
+
81
+ # Public: Kicks off the CLI
82
+ #
83
+ # Examples
84
+ #
85
+ # parse
86
+ #
87
+ # Returns nothing.
88
+ def parse
26
89
  cli = OptionParser.new do |o|
27
90
  o.banner = "Usage #{PROGRAM_NAME} [add|sort|tag|clear|open]"
28
91
  o.program_name = PROGRAM_NAME
@@ -39,37 +102,50 @@ module Ldgr
39
102
  o.define '-p', '--payee=PAYEE', String, 'the payee of the transaction'
40
103
  end
41
104
 
42
- config = defaults
43
105
  command = String(cli.parse(ARGV, into: config)[0])
44
- binding.irb
45
- send(command, config) if COMMANDS.include? command
106
+ send(command) if commands.include? command
46
107
  end
47
108
 
48
- def self.add(config)
109
+ # Public: Adds a transaction to the transactions_file.
110
+ #
111
+ # Examples
112
+ #
113
+ # add
114
+ #
115
+ # Returns nothing.
116
+ def add
49
117
  error_policy = ->(key) { fail "You need to provide a value for #{key.to_s}." }
50
118
 
51
119
  transaction = Transaction.new do |t|
52
- date = String(config.fetch(:date) { Date.today } )
53
- effective = String(config.fetch(:effective) { Date.today })
120
+ date = String(config.fetch(:date) { |key| error_policy.call(key) })
121
+ effective = String(config.fetch(:effective) { |key| error_policy.call(key) })
54
122
 
55
123
  t.payee = config.fetch(:payee) { |key| error_policy.call(key) }
56
124
  t.account = config.fetch(:account) { |key| error_policy.call(key) }
57
125
  t.amount = config.fetch(:amount) { |key| error_policy.call(key) }
58
- t.currency = config.fetch(:currency) { defaults.fetch('currency') { '$' } }
59
- t.equity = config.fetch(:equity) { defaults.fetch('equity') { 'Cash' } }
126
+ t.currency = config.fetch(:currency) { config.fetch(:currency) }
127
+ t.equity = config.fetch(:equity) { config.fetch(:equity) }
60
128
  t.cleared = config[:cleared] ? '* ' : ''
61
129
  t.date = date == effective ? date : date << '=' << effective
62
130
  end
63
131
 
64
- File.open(FILE, 'a') { |file| file.puts transaction }
132
+ File.open(transactions_file, 'a') { |file| file.puts transaction }
65
133
  end
66
134
 
67
- def self.clear(config)
135
+ # Public: Runs through all uncleared transactions that are passed
136
+ # their effective date and offers to clear them.
137
+ #
138
+ # Examples
139
+ #
140
+ # clear
141
+ #
142
+ # Returns nothing.
143
+ def clear
68
144
  output = ''
69
145
  pattern = /((^\d{,4}-\d{,2}-\d{,2})(=\d{,4}-\d{,2}-\d{,2})?) ([^\*]+)/
70
146
  count = 0
71
147
 
72
- File.open(FILE, 'r') do |transactions|
148
+ File.open(transactions_file, 'r') do |transactions|
73
149
  transactions.each_line do |transaction|
74
150
  match = pattern.match(transaction)
75
151
  if match && match[3]
@@ -90,16 +166,23 @@ module Ldgr
90
166
  output << transaction
91
167
  end
92
168
  end
93
- IO.write(FILE, output)
169
+ IO.write(transactions_file, output)
94
170
  end
95
171
 
96
- def self.tag(config)
172
+ # Public: Runs through all transactions with only Expenses set as the account and lets you enter an account name.
173
+ #
174
+ # Examples
175
+ #
176
+ # tag
177
+ #
178
+ # Returns nothing.
179
+ def tag
97
180
  output = ''
98
181
  pattern = /(^\s+Expenses[^:])\s*(¥.+)/
99
182
  count = 0
100
183
  previous = ''
101
184
 
102
- File.open(FILE, 'r') do |transactions|
185
+ File.open(transactions_file, 'r') do |transactions|
103
186
  transactions.each_line do |transaction|
104
187
  match = pattern.match(transaction)
105
188
  if match
@@ -112,11 +195,18 @@ module Ldgr
112
195
  output << transaction
113
196
  end
114
197
  end
115
- IO.write(FILE, output)
198
+ IO.write(transactions_file, output)
116
199
  end
117
200
 
118
- def self.sort(config)
119
- text = File.read(FILE).gsub(/\n+|\r+/, "\n").squeeze("\n").strip
201
+ # Public: Sorts all transactions by date.
202
+ #
203
+ # Examples
204
+ #
205
+ # sort
206
+ #
207
+ # Returns nothing.
208
+ def sort
209
+ text = File.read(transactions_file).gsub(/\n+|\r+/, "\n").squeeze("\n").strip
120
210
  scanner = StringScanner.new(text)
121
211
  results = []
122
212
 
@@ -125,13 +215,21 @@ module Ldgr
125
215
  scanner.skip_until(OTHER_MATCH)
126
216
  end
127
217
 
128
- File.open(FILE, 'w') do |file|
218
+ File.open(transactions_file, 'w') do |file|
129
219
  file.puts results.sort
130
220
  end
131
221
  end
132
222
 
133
- def self.open(_)
134
- def self.open_file(file_to_open)
223
+ # Public: Opens a settings file from ~/.config/ledger
224
+ #
225
+ # Examples
226
+ #
227
+ # open accounts
228
+ # # => accounts file opens in $EDITOR
229
+ #
230
+ # Returns nothing.
231
+ def open
232
+ def open_file(file_to_open)
135
233
  checked_file = "#{FILEBASE}#{file_to_open}.dat"
136
234
  raise "#{checked_file} doesn't exist." unless Pathname(checked_file).exist?
137
235
  system(ENV['EDITOR'], checked_file)
@@ -140,20 +238,41 @@ module Ldgr
140
238
  open_file(ARGV[1])
141
239
  end
142
240
 
143
- def self.defaults(config_file=CONFIG_FILE)
144
- LDGR_DEFAULTS.merge(YAML.load_file(config_file).to_h)
241
+ # Public: ldgr's default configuration options
242
+ #
243
+ # Examples
244
+ #
245
+ # defaults
246
+ # # => {all the configuration options}
247
+ #
248
+ # Returns a hash of default configuration options.
249
+ def defaults
250
+ {
251
+ currency: '$',
252
+ equity: 'Cash',
253
+ effective: Date.today,
254
+ date: Date.today,
255
+ cleared: false,
256
+ transactions_file: FILEBASE + 'transactions.dat'
257
+ }
145
258
  end
146
259
 
260
+ # Private: Prepares users' file system for ldgr.
261
+ #
262
+ # Returns nothing.
147
263
  def self.setup
148
264
  unless config_exist?
149
265
  FileUtils.mkdir_p(FILEBASE)
150
- SETUP_FILES.each do |file|
266
+ setup_files.each do |file|
151
267
  FileUtils.touch("#{FILEBASE}#{file}")
152
268
  end
153
269
  end
154
270
  end
155
271
 
156
- def self.config_exist?(setup_files=SETUP_FILES)
272
+ # Private: Checks if user already has setup files created.
273
+ #
274
+ # Returns nothing.
275
+ def self.config_exist?
157
276
  setup_files.each do |file|
158
277
  return false unless Pathname("#{FILEBASE}#{file}").exist?
159
278
  end
data/lib/ldgr/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Ldgr
2
- VERSION = "0.1.8"
2
+ VERSION = "0.1.9"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ldgr
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.8
4
+ version: 0.1.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brandon Pittman
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-02-07 00:00:00.000000000 Z
11
+ date: 2017-02-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: highline
@@ -90,7 +90,6 @@ extra_rdoc_files: []
90
90
  files:
91
91
  - ".gitignore"
92
92
  - ".travis.yml"
93
- - CODE_OF_CONDUCT.md
94
93
  - Gemfile
95
94
  - LICENSE.txt
96
95
  - README.md
data/CODE_OF_CONDUCT.md DELETED
@@ -1,74 +0,0 @@
1
- # Contributor Covenant Code of Conduct
2
-
3
- ## Our Pledge
4
-
5
- In the interest of fostering an open and welcoming environment, we as
6
- contributors and maintainers pledge to making participation in our project and
7
- our community a harassment-free experience for everyone, regardless of age, body
8
- size, disability, ethnicity, gender identity and expression, level of experience,
9
- nationality, personal appearance, race, religion, or sexual identity and
10
- orientation.
11
-
12
- ## Our Standards
13
-
14
- Examples of behavior that contributes to creating a positive environment
15
- include:
16
-
17
- * Using welcoming and inclusive language
18
- * Being respectful of differing viewpoints and experiences
19
- * Gracefully accepting constructive criticism
20
- * Focusing on what is best for the community
21
- * Showing empathy towards other community members
22
-
23
- Examples of unacceptable behavior by participants include:
24
-
25
- * The use of sexualized language or imagery and unwelcome sexual attention or
26
- advances
27
- * Trolling, insulting/derogatory comments, and personal or political attacks
28
- * Public or private harassment
29
- * Publishing others' private information, such as a physical or electronic
30
- address, without explicit permission
31
- * Other conduct which could reasonably be considered inappropriate in a
32
- professional setting
33
-
34
- ## Our Responsibilities
35
-
36
- Project maintainers are responsible for clarifying the standards of acceptable
37
- behavior and are expected to take appropriate and fair corrective action in
38
- response to any instances of unacceptable behavior.
39
-
40
- Project maintainers have the right and responsibility to remove, edit, or
41
- reject comments, commits, code, wiki edits, issues, and other contributions
42
- that are not aligned to this Code of Conduct, or to ban temporarily or
43
- permanently any contributor for other behaviors that they deem inappropriate,
44
- threatening, offensive, or harmful.
45
-
46
- ## Scope
47
-
48
- This Code of Conduct applies both within project spaces and in public spaces
49
- when an individual is representing the project or its community. Examples of
50
- representing a project or community include using an official project e-mail
51
- address, posting via an official social media account, or acting as an appointed
52
- representative at an online or offline event. Representation of a project may be
53
- further defined and clarified by project maintainers.
54
-
55
- ## Enforcement
56
-
57
- Instances of abusive, harassing, or otherwise unacceptable behavior may be
58
- reported by contacting the project team at brandon@brandonpittman.net. All
59
- complaints will be reviewed and investigated and will result in a response that
60
- is deemed necessary and appropriate to the circumstances. The project team is
61
- obligated to maintain confidentiality with regard to the reporter of an incident.
62
- Further details of specific enforcement policies may be posted separately.
63
-
64
- Project maintainers who do not follow or enforce the Code of Conduct in good
65
- faith may face temporary or permanent repercussions as determined by other
66
- members of the project's leadership.
67
-
68
- ## Attribution
69
-
70
- This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71
- available at [http://contributor-covenant.org/version/1/4][version]
72
-
73
- [homepage]: http://contributor-covenant.org
74
- [version]: http://contributor-covenant.org/version/1/4/