journal-cli 1.0.9 → 1.0.10
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +6 -22
- data/Gemfile.lock +1 -1
- data/README.md +8 -0
- data/bin/journal +45 -37
- data/lib/journal-cli/checkin.rb +82 -139
- data/lib/journal-cli/question.rb +99 -0
- data/lib/journal-cli/section.rb +47 -0
- data/lib/journal-cli/sections.rb +13 -0
- data/lib/journal-cli/version.rb +1 -1
- data/lib/journal-cli.rb +23 -4
- data/src/_README.md +8 -0
- metadata +4 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: daaf3cad805bf34bae2691d8d5738316aef4318bf9f6a9562fcbc38c27f0e3be
|
4
|
+
data.tar.gz: 861bca0aae3312d48dd070dc5c88cffadb709242e9374f25856ac6b5b5189cfd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0c982533e8d04247ccfffe560549f01ea57725bfcc0391294ece7bb32adf56fdee95589700fcdb6ca855dddaa446dfe06c6d15a394befd231683680194678670
|
7
|
+
data.tar.gz: 787c597423d1ef820068b6498fd5004edf17e19c2e6f723e69b6feca919c8cc8bbe9127304749ce3c88b320d69e330823f51e0de14f7c1995e0c2d1a98fdc690
|
data/CHANGELOG.md
CHANGED
@@ -1,30 +1,14 @@
|
|
1
|
-
### 1.0.
|
2
|
-
|
3
|
-
2023-09-06 11:58
|
4
|
-
|
5
|
-
#### NEW
|
6
|
-
|
7
|
-
- If the second argument is a natural language date, use the parsed result instead of the current time for the entry
|
8
|
-
|
9
|
-
### 1.0.8
|
10
|
-
|
11
|
-
2023-09-06 11:56
|
1
|
+
### 1.0.10
|
12
2
|
|
13
|
-
|
14
|
-
|
15
|
-
- If the second argument is a natural language date, use the parsed result instead of the current time for the entry
|
3
|
+
2023-09-06 16:03
|
16
4
|
|
17
|
-
|
5
|
+
#### IMPROVED
|
18
6
|
|
19
|
-
|
20
|
-
|
21
|
-
#### NEW
|
7
|
+
- Refactoring code
|
22
8
|
|
23
|
-
|
24
|
-
|
25
|
-
### 1.0.6
|
9
|
+
### 1.0.9
|
26
10
|
|
27
|
-
2023-09-06 11:
|
11
|
+
2023-09-06 11:58
|
28
12
|
|
29
13
|
#### NEW
|
30
14
|
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -128,3 +128,11 @@ Answers will always be written to `~/.local/share/journal/[KEY].json` (where [KE
|
|
128
128
|
|
129
129
|
At present there's no tool for querying the dataset created. You just need to parse the JSON and use your language of choice to extract the data. Numeric entries are stored as numbers, and every entry is timestamped, so you should be able to do some advanced analysis once you have enough data.
|
130
130
|
|
131
|
+
### Answering prompts
|
132
|
+
|
133
|
+
Questions with numeric answers will have a valid range assigned. Enter just a number within the range and hit return.
|
134
|
+
|
135
|
+
Questions with type 'string' or 'text' will save when you hit return. Pressing return without typing anything will leave that answer blank, and it will be ignored when exporting to Markdown or Day One (an empty value will exist in the JSON database).
|
136
|
+
|
137
|
+
When using the mutiline type, you'll get an edit field that responds to most control-key navigation and allows insertion and movement. To save a multiline field, press Escape or type CTRL-d.
|
138
|
+
|
data/bin/journal
CHANGED
@@ -3,44 +3,52 @@
|
|
3
3
|
$LOAD_PATH.unshift File.join(__dir__, '..', 'lib')
|
4
4
|
require 'journal-cli'
|
5
5
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
6
|
+
module Journal
|
7
|
+
class << self
|
8
|
+
def usage
|
9
|
+
puts "journal v#{Journal::VERSION}"
|
10
|
+
puts
|
11
|
+
puts 'Usage: journal [type] [date]'
|
12
|
+
puts
|
13
|
+
puts 'Available journal types:'
|
14
|
+
config = Journal.config
|
15
|
+
puts(config['journals'].keys.map { |k| "- #{k}" })
|
16
|
+
end
|
15
17
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
18
|
+
def run(args)
|
19
|
+
if args.count.zero?
|
20
|
+
puts "No journal specified"
|
21
|
+
usage
|
22
|
+
Process.exit 1
|
23
|
+
end
|
21
24
|
|
22
|
-
case
|
23
|
-
when /(-v|--version)/
|
24
|
-
|
25
|
-
|
26
|
-
when /(help|-h|--help)/
|
27
|
-
|
28
|
-
|
29
|
-
end
|
25
|
+
case args[0]
|
26
|
+
when /(-v|--version)/
|
27
|
+
puts "journal v#{Journal::VERSION}"
|
28
|
+
Process.exit 0
|
29
|
+
when /(help|-h|--help)/
|
30
|
+
usage
|
31
|
+
Process.exit 0
|
32
|
+
end
|
30
33
|
|
31
|
-
journal =
|
32
|
-
|
33
|
-
date = if
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
if
|
40
|
-
|
41
|
-
|
42
|
-
else
|
43
|
-
|
44
|
-
|
45
|
-
|
34
|
+
journal = args.shift
|
35
|
+
|
36
|
+
date = if args.length.positive?
|
37
|
+
Chronic.parse(args.join(' '), future: false)
|
38
|
+
else
|
39
|
+
Time.now
|
40
|
+
end
|
41
|
+
|
42
|
+
if Journal.config['journals'].key?(journal)
|
43
|
+
checkin = Journal::Checkin.new(journal, date)
|
44
|
+
checkin.go
|
45
|
+
else
|
46
|
+
puts "Journal #{journal} not found"
|
47
|
+
usage
|
48
|
+
Process.exit 1
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
46
52
|
end
|
53
|
+
|
54
|
+
Journal.run(ARGV)
|
data/lib/journal-cli/checkin.rb
CHANGED
@@ -1,23 +1,18 @@
|
|
1
1
|
module Journal
|
2
2
|
# Main class
|
3
3
|
class Checkin
|
4
|
-
attr_reader :key, :date, :data, :config, :journal, :title, :output
|
4
|
+
attr_reader :key, :date, :data, :config, :journal, :sections, :title, :output
|
5
5
|
|
6
|
-
def initialize
|
7
|
-
config = File.expand_path('~/.config/journal/journals.yaml')
|
8
|
-
raise StandardError, 'No journals configured' unless File.exist?(config)
|
9
|
-
|
10
|
-
@config = YAML.load(IO.read(config))
|
11
|
-
end
|
12
|
-
|
13
|
-
def start(journal, date)
|
6
|
+
def initialize(journal, date)
|
14
7
|
@key = journal
|
15
8
|
@output = []
|
16
9
|
@date = date
|
10
|
+
@date.localtime
|
17
11
|
|
18
|
-
raise StandardError, "No journal with key #{@key} found" unless
|
12
|
+
raise StandardError, "No journal with key #{@key} found" unless Journal.config['journals'].key? @key
|
19
13
|
|
20
|
-
@journal =
|
14
|
+
@journal = Journal.config['journals'][@key]
|
15
|
+
@sections = Sections.new(@journal['sections'])
|
21
16
|
|
22
17
|
@data = {}
|
23
18
|
meridian = @date.hour < 13 ? 'AM' : 'PM'
|
@@ -44,93 +39,69 @@ module Journal
|
|
44
39
|
@output << "\n---\n"
|
45
40
|
end
|
46
41
|
|
47
|
-
def ask_question(q)
|
48
|
-
res = case q['type']
|
49
|
-
when /^(int|num)/i
|
50
|
-
min = q['min'] || 1
|
51
|
-
max = q['max'] || 5
|
52
|
-
get_number(q['prompt'], min: min, max: max)
|
53
|
-
when /^(text|string|line)/i
|
54
|
-
puts q['prompt']
|
55
|
-
add_prompt = q['secondary_prompt'] || nil
|
56
|
-
get_line(q['prompt'], add_prompt: add_prompt)
|
57
|
-
when /^(weather|forecast)/i
|
58
|
-
Weather.new(@config['weather_api'], @config['zip'])
|
59
|
-
when /^multi/
|
60
|
-
puts q['prompt']
|
61
|
-
add_prompt = q['secondary_prompt'] || nil
|
62
|
-
get_lines(q['prompt'], add_prompt: add_prompt)
|
63
|
-
end
|
64
|
-
|
65
|
-
res
|
66
|
-
end
|
67
|
-
|
68
42
|
def go
|
69
|
-
|
70
|
-
@journal['sections'].each do |s|
|
71
|
-
results[s['key']] = {
|
72
|
-
title: s['title'],
|
73
|
-
answers: {}
|
74
|
-
}
|
43
|
+
@sections.each { |key, section| @data[key] = section }
|
75
44
|
|
76
|
-
|
77
|
-
|
78
|
-
res = results[s['key']][:answers]
|
79
|
-
keys = q['key'].split(/\./)
|
80
|
-
keys.each_with_index do |key, i|
|
81
|
-
next if i == keys.count - 1
|
45
|
+
save_data
|
46
|
+
save_day_one_entry if @journal['dayone']
|
82
47
|
|
83
|
-
|
84
|
-
res = res[key]
|
85
|
-
end
|
48
|
+
return unless @journal['markdown']
|
86
49
|
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
50
|
+
case @journal['markdown']
|
51
|
+
when /^da(y|ily)/
|
52
|
+
save_daily_markdown
|
53
|
+
when /^(ind|sep)/
|
54
|
+
save_individual_markdown
|
55
|
+
else
|
56
|
+
save_single_markdown
|
92
57
|
end
|
58
|
+
end
|
93
59
|
|
94
|
-
|
60
|
+
def save_day_one_entry
|
61
|
+
cmd = ['dayone2']
|
62
|
+
cmd << %(-j "#{@journal['journal']}") if @journal.key?('journal')
|
63
|
+
cmd << %(-t #{@journal['tags'].join(' ')}) if @journal.key?('tags')
|
64
|
+
cmd << %(-date "#{@date.strftime('%Y-%m-%d %I:%M %p')}")
|
65
|
+
`echo #{Shellwords.escape(to_markdown(yaml: false, title: true))} | #{cmd.join(' ')} -- new`
|
66
|
+
end
|
95
67
|
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
68
|
+
def save_single_markdown
|
69
|
+
dir = File.expand_path('~/.local/share/journal/entries/')
|
70
|
+
FileUtils.mkdir_p(dir) unless File.directory?(dir)
|
71
|
+
filename = "#{@key}.md"
|
72
|
+
@date.localtime
|
73
|
+
target = File.join(dir, filename)
|
74
|
+
File.open(target, 'a') do |f|
|
75
|
+
f.puts
|
76
|
+
f.puts "## #{@title} #{@date.strftime('%x %X')}"
|
77
|
+
f.puts
|
78
|
+
f.puts to_markdown(yaml: false, title: false)
|
102
79
|
end
|
80
|
+
puts "Saved #{target}"
|
81
|
+
end
|
103
82
|
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
end
|
115
|
-
elsif @journal['markdown'] =~ /^(ind|separate)/
|
116
|
-
dir = File.expand_path("~/.local/share/journal/entries/#{@key}")
|
117
|
-
FileUtils.mkdir_p(dir) unless File.directory?(dir)
|
118
|
-
filename = @date.strftime('%Y-%m-%d_%H:%M.md')
|
119
|
-
File.open(File.join(dir, filename), 'w') { |f| f.puts to_markdown(yaml: true, title: true) }
|
120
|
-
else
|
121
|
-
dir = File.expand_path('~/.local/share/journal/entries/')
|
122
|
-
FileUtils.mkdir_p(dir) unless File.directory?(dir)
|
123
|
-
filename = "#{@key}.md"
|
124
|
-
File.open(File.join(dir, filename), 'a') do |f|
|
125
|
-
f.puts
|
126
|
-
f.puts "## #{@title} #{@date.strftime('%x %X')}"
|
127
|
-
f.puts
|
128
|
-
f.puts to_markdown(yaml: false, title: false)
|
129
|
-
end
|
130
|
-
end
|
83
|
+
def save_daily_markdown
|
84
|
+
dir = File.expand_path("~/.local/share/journal/entries/#{@key}")
|
85
|
+
FileUtils.mkdir_p(dir) unless File.directory?(dir)
|
86
|
+
@date.localtime
|
87
|
+
filename = "#{@date.strftime('%Y-%m-%d')}.md"
|
88
|
+
target = File.join(dir, filename)
|
89
|
+
if File.exist? target
|
90
|
+
File.open(target, 'a') { |f| f.puts to_markdown(yaml: false, title: true, date: false, time: true) }
|
91
|
+
else
|
92
|
+
File.open(target, 'w') { |f| f.puts to_markdown(yaml: true, title: true, date: false, time: true) }
|
131
93
|
end
|
94
|
+
puts "Saved #{target}"
|
95
|
+
end
|
132
96
|
|
133
|
-
|
97
|
+
def save_individual_markdown
|
98
|
+
dir = File.expand_path("~/.local/share/journal/entries/#{@key}")
|
99
|
+
FileUtils.mkdir_p(dir) unless File.directory?(dir)
|
100
|
+
@date.localtime
|
101
|
+
filename = @date.strftime('%Y-%m-%d_%H:%M.md')
|
102
|
+
target = File.join(dir, filename)
|
103
|
+
File.open(target, 'w') { |f| f.puts to_markdown(yaml: true, title: true) }
|
104
|
+
puts "Saved #{target}"
|
134
105
|
end
|
135
106
|
|
136
107
|
def print_answer(prompt, type, key, data)
|
@@ -154,6 +125,7 @@ module Journal
|
|
154
125
|
@output = []
|
155
126
|
|
156
127
|
if yaml
|
128
|
+
@date.localtime
|
157
129
|
@output << <<~EOYAML
|
158
130
|
---
|
159
131
|
title: #{@title}
|
@@ -174,21 +146,22 @@ module Journal
|
|
174
146
|
end
|
175
147
|
end
|
176
148
|
|
177
|
-
@
|
178
|
-
section
|
149
|
+
@sections.each do |key, section|
|
150
|
+
answers = section.answers
|
151
|
+
section section.title
|
179
152
|
|
180
|
-
|
181
|
-
if
|
182
|
-
res =
|
183
|
-
keys =
|
153
|
+
section.questions.each do |question|
|
154
|
+
if question.key =~ /\./
|
155
|
+
res = section.answers.dup
|
156
|
+
keys = question.key.split(/\./)
|
184
157
|
keys.each_with_index do |key, i|
|
185
158
|
next if i == keys.count - 1
|
186
159
|
|
187
160
|
res = res[key]
|
188
161
|
end
|
189
|
-
print_answer(
|
162
|
+
print_answer(question.prompt, question.type, keys.last, res)
|
190
163
|
else
|
191
|
-
print_answer(
|
164
|
+
print_answer(question.prompt, question.type, question.key, section.answers)
|
192
165
|
end
|
193
166
|
end
|
194
167
|
end
|
@@ -197,6 +170,7 @@ module Journal
|
|
197
170
|
end
|
198
171
|
|
199
172
|
def save_data
|
173
|
+
@date.localtime
|
200
174
|
db = File.expand_path("~/.local/share/journal/#{@key}.json")
|
201
175
|
data = if File.exist?(db)
|
202
176
|
JSON.parse(IO.read(db))
|
@@ -206,57 +180,26 @@ module Journal
|
|
206
180
|
date = @date.utc
|
207
181
|
output = {}
|
208
182
|
|
209
|
-
@data.each do |
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
183
|
+
@data.each do |jk, journal|
|
184
|
+
output[jk] = {}
|
185
|
+
journal.answers.each do |k, v|
|
186
|
+
if v.is_a? Hash
|
187
|
+
output[jk][k] = {}
|
188
|
+
v.each do |key, value|
|
189
|
+
output[jk][k][key] = case value.class.to_s
|
190
|
+
when /Weather/
|
191
|
+
{ 'high' => value.data[:high], 'low' => value.data[:low], 'condition' => value.data[:condition] }
|
192
|
+
else
|
193
|
+
value
|
194
|
+
end
|
220
195
|
end
|
221
196
|
else
|
222
|
-
output[
|
197
|
+
output[jk][k] = v
|
223
198
|
end
|
224
199
|
end
|
225
200
|
end
|
226
201
|
data << { 'date' => date, 'data' => output }
|
227
202
|
File.open(db, 'w') { |f| f.puts JSON.pretty_generate(data) }
|
228
203
|
end
|
229
|
-
|
230
|
-
def get_number(prompt, min: 1, max: 5)
|
231
|
-
puts "#{prompt} (#{min}-#{max})"
|
232
|
-
res = `gum input --placeholder "#{prompt} (#{min}-#{max})"`.strip
|
233
|
-
return nil if res.strip.empty?
|
234
|
-
|
235
|
-
res = res.to_i
|
236
|
-
|
237
|
-
res = get_number(prompt, min: min, max: max) if res < min || res > max
|
238
|
-
res
|
239
|
-
end
|
240
|
-
|
241
|
-
def get_line(prompt, add_prompt: nil)
|
242
|
-
output = []
|
243
|
-
puts prompt
|
244
|
-
line = `gum input --placeholder "#{prompt} (blank to end editing)"`
|
245
|
-
return output.join("\n") if line =~ /^ *$/
|
246
|
-
|
247
|
-
output << line
|
248
|
-
output << get_line(add_prompt, add_prompt: add_prompt) if add_prompt
|
249
|
-
output.join("\n")
|
250
|
-
end
|
251
|
-
|
252
|
-
def get_lines(prompt, add_prompt: nil)
|
253
|
-
output = []
|
254
|
-
line = `gum write --placeholder "#{prompt}" --width 80 --char-limit 0`
|
255
|
-
return output.join("\n") if line.strip.empty?
|
256
|
-
|
257
|
-
output << line
|
258
|
-
output << get_lines(add_prompt, add_prompt: add_prompt) if add_prompt
|
259
|
-
output.join("\n")
|
260
|
-
end
|
261
204
|
end
|
262
205
|
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Journal
|
4
|
+
# Individual question
|
5
|
+
class Question
|
6
|
+
attr_reader :key, :type, :min, :max, :prompt, :secondary_prompt
|
7
|
+
|
8
|
+
##
|
9
|
+
## Initializes the given question.
|
10
|
+
##
|
11
|
+
## @param question [Hash] The question with key, prompt, and type, optionally min and max
|
12
|
+
##
|
13
|
+
## @return [Question] the question object
|
14
|
+
##
|
15
|
+
def initialize(question)
|
16
|
+
@key = question['key']
|
17
|
+
@type = question['type']
|
18
|
+
@min = question['min']&.to_i || 1
|
19
|
+
@max = question['max']&.to_i || 5
|
20
|
+
@prompt = question['prompt']
|
21
|
+
@secondary_prompt = question['secondary_prompt'] || nil
|
22
|
+
end
|
23
|
+
|
24
|
+
##
|
25
|
+
## Ask the question, prompting for input based on type
|
26
|
+
##
|
27
|
+
## @return [Number, String] the response based on @type
|
28
|
+
##
|
29
|
+
def ask
|
30
|
+
case @type
|
31
|
+
when /^(int|num)/i
|
32
|
+
read_number
|
33
|
+
when /^(text|string|line)/i
|
34
|
+
read_line
|
35
|
+
when /^(weather|forecast)/i
|
36
|
+
Weather.new(Journal.config['weather_api'], Journal.config['zip'])
|
37
|
+
when /^multi/
|
38
|
+
read_lines
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
##
|
43
|
+
## Read a numeric entry
|
44
|
+
##
|
45
|
+
## @return [Number] integer response
|
46
|
+
##
|
47
|
+
def read_number
|
48
|
+
puts "#{@prompt} (#{@min}-#{@max})"
|
49
|
+
res = `gum input --placeholder "#{@prompt} (#{@min}-#{@max})"`.strip
|
50
|
+
return nil if res.strip.empty?
|
51
|
+
|
52
|
+
res = res.to_i
|
53
|
+
|
54
|
+
res = read_number if res < @min || res > @max
|
55
|
+
res
|
56
|
+
end
|
57
|
+
|
58
|
+
##
|
59
|
+
## Reads a line.
|
60
|
+
##
|
61
|
+
## @param prompt [String] If not nil, will trigger
|
62
|
+
## asking for a secondary response
|
63
|
+
## until a blank entry is given
|
64
|
+
##
|
65
|
+
## @return [String] the single-line response
|
66
|
+
##
|
67
|
+
def read_line(prompt: nil)
|
68
|
+
output = []
|
69
|
+
puts prompt.nil? ? @prompt : @secondary_prompt
|
70
|
+
|
71
|
+
line = `gum input --placeholder "#{@prompt} (blank to end editing)"`
|
72
|
+
return output.join("\n") if line =~ /^ *$/
|
73
|
+
|
74
|
+
output << line
|
75
|
+
output << read_line(prompt: @secondary_prompt) unless @secondary_prompt.nil?
|
76
|
+
output.join("\n").strip
|
77
|
+
end
|
78
|
+
|
79
|
+
##
|
80
|
+
## Reads multiple lines.
|
81
|
+
##
|
82
|
+
## @param prompt [String] if not nil, will trigger
|
83
|
+
## asking for a secondary response
|
84
|
+
## until a blank entry is given
|
85
|
+
##
|
86
|
+
## @return [String] the multi-line response
|
87
|
+
##
|
88
|
+
def read_lines(prompt: nil)
|
89
|
+
output = []
|
90
|
+
puts prompt.nil? ? @prompt : @secondary_prompt
|
91
|
+
line = `gum write --placeholder "#{prompt}" --width 80 --char-limit 0`
|
92
|
+
return output.join("\n") if line.strip.empty?
|
93
|
+
|
94
|
+
output << line
|
95
|
+
output << read_lines(prompt: @secondary_prompt) unless @secondary_prompt.nil?
|
96
|
+
output.join("\n").strip
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Journal
|
4
|
+
class Section
|
5
|
+
attr_accessor :key, :title, :questions, :answers
|
6
|
+
|
7
|
+
##
|
8
|
+
## Initializes the given section.
|
9
|
+
##
|
10
|
+
## @param section [Hash] The section as defined in
|
11
|
+
## configuration
|
12
|
+
##
|
13
|
+
## @return [Section] the configured section
|
14
|
+
##
|
15
|
+
def initialize(section)
|
16
|
+
@key = section['key']
|
17
|
+
@title = section['title']
|
18
|
+
@questions = section['questions'].map { |question| Question.new(question) }
|
19
|
+
@answers = {}
|
20
|
+
ask_questions
|
21
|
+
end
|
22
|
+
|
23
|
+
##
|
24
|
+
## Ask the questions detailed in the 'questions' section of the configuration
|
25
|
+
##
|
26
|
+
## @return [Hash] the question responses
|
27
|
+
##
|
28
|
+
def ask_questions
|
29
|
+
@questions.each do |question|
|
30
|
+
if question.key =~ /\./
|
31
|
+
res = @answers
|
32
|
+
keys = question.key.split(/\./)
|
33
|
+
keys.each_with_index do |key, i|
|
34
|
+
next if i == keys.count - 1
|
35
|
+
|
36
|
+
res[key] = {} unless res.key?(key)
|
37
|
+
res = res[key]
|
38
|
+
end
|
39
|
+
|
40
|
+
res[keys.last] = question.ask
|
41
|
+
else
|
42
|
+
@answers[question.key] = question.ask
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
data/lib/journal-cli/version.rb
CHANGED
data/lib/journal-cli.rb
CHANGED
@@ -7,7 +7,26 @@ require 'yaml'
|
|
7
7
|
require 'chronic'
|
8
8
|
require 'fileutils'
|
9
9
|
|
10
|
-
require_relative
|
11
|
-
require_relative
|
12
|
-
require_relative
|
13
|
-
require_relative
|
10
|
+
require_relative 'journal-cli/version'
|
11
|
+
require_relative 'journal-cli/data'
|
12
|
+
require_relative 'journal-cli/weather'
|
13
|
+
require_relative 'journal-cli/checkin'
|
14
|
+
require_relative 'journal-cli/sections'
|
15
|
+
require_relative 'journal-cli/section'
|
16
|
+
require_relative 'journal-cli/question'
|
17
|
+
|
18
|
+
# Main Journal module
|
19
|
+
module Journal
|
20
|
+
class << self
|
21
|
+
def config
|
22
|
+
unless @config
|
23
|
+
config = File.expand_path('~/.config/journal/journals.yaml')
|
24
|
+
raise StandardError, 'No journals configured' unless File.exist?(config)
|
25
|
+
|
26
|
+
@config = YAML.load(IO.read(config))
|
27
|
+
end
|
28
|
+
|
29
|
+
@config
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
data/src/_README.md
CHANGED
@@ -132,6 +132,14 @@ Answers will always be written to `~/.local/share/journal/[KEY].json` (where [KE
|
|
132
132
|
|
133
133
|
At present there's no tool for querying the dataset created. You just need to parse the JSON and use your language of choice to extract the data. Numeric entries are stored as numbers, and every entry is timestamped, so you should be able to do some advanced analysis once you have enough data.
|
134
134
|
|
135
|
+
### Answering prompts
|
136
|
+
|
137
|
+
Questions with numeric answers will have a valid range assigned. Enter just a number within the range and hit return.
|
138
|
+
|
139
|
+
Questions with type 'string' or 'text' will save when you hit return. Pressing return without typing anything will leave that answer blank, and it will be ignored when exporting to Markdown or Day One (an empty value will exist in the JSON database).
|
140
|
+
|
141
|
+
When using the mutiline type, you'll get an edit field that responds to most control-key navigation and allows insertion and movement. To save a multiline field, press Escape or type CTRL-d.
|
142
|
+
|
135
143
|
<!--END README-->
|
136
144
|
## Contributing
|
137
145
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: journal-cli
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.10
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Brett Terpstra
|
@@ -174,6 +174,9 @@ files:
|
|
174
174
|
- lib/journal-cli.rb
|
175
175
|
- lib/journal-cli/checkin.rb
|
176
176
|
- lib/journal-cli/data.rb
|
177
|
+
- lib/journal-cli/question.rb
|
178
|
+
- lib/journal-cli/section.rb
|
179
|
+
- lib/journal-cli/sections.rb
|
177
180
|
- lib/journal-cli/version.rb
|
178
181
|
- lib/journal-cli/weather.rb
|
179
182
|
- src/_README.md
|