journal-cli 1.0.9 → 1.0.11

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bbc1e82ebcb01ece20b52ce550ec1ecbfb73c6b6ca42aed66b370196ab56fd5b
4
- data.tar.gz: e1f43b0ff725b58c12b41592acc432f7e81b4beb2fcc894376f81a9538b6adec
3
+ metadata.gz: 0c283ee76be0875ecc6c36ed2902dd5b122803f1163095773e71c1e4fee2bc32
4
+ data.tar.gz: 3c5c01c37a4c9ed0972f5eaa18192cb9e910f098e3fafe7e6630f335de1eb050
5
5
  SHA512:
6
- metadata.gz: d369cf8bb7b706d71c0c3b30900e2fd784d8475cf1380f3b19c4b3a1ec36b01cb1e51055dd33ba259247de6929abdd689e936bb6d66c4ba21c99765537d5a5c2
7
- data.tar.gz: 9410b47a96eee2376679ecb67d6e9af75323e49feb93993c2288276908685c08a43459184a32889824bd839fdce8bf22353ec7831f4063920b9075029b1c8de9
6
+ metadata.gz: b703b2626cce5ade77b961e7a4c14cc0cfbfd32ace4ee95c80ac20412a6b0fcecc7f71879d0377d7e7b6684731a28831606aa8ee87b57fa8906483b771601200
7
+ data.tar.gz: a8c4692c942f47dd3679d054b8e8b6dadf4e40a6460602d5d3ea0f7c39ad9b4e776554b2e410185f690260b0a03682a9047cbf461937c8bd037666c267ab45a2
data/CHANGELOG.md CHANGED
@@ -1,30 +1,22 @@
1
- ### 1.0.9
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
1
+ ### 1.0.11
8
2
 
9
- ### 1.0.8
3
+ 2023-09-06 16:37
10
4
 
11
- 2023-09-06 11:56
5
+ #### IMPROVED
12
6
 
13
- #### NEW
7
+ - Write a demo config file for editing
14
8
 
15
- - If the second argument is a natural language date, use the parsed result instead of the current time for the entry
9
+ ### 1.0.10
16
10
 
17
- ### 1.0.7
11
+ 2023-09-06 16:03
18
12
 
19
- 2023-09-06 11:56
13
+ #### IMPROVED
20
14
 
21
- #### NEW
15
+ - Refactoring code
22
16
 
23
- - If the second argument is a natural language date, use the parsed result instead of the current time for the entry
24
-
25
- ### 1.0.6
17
+ ### 1.0.9
26
18
 
27
- 2023-09-06 11:54
19
+ 2023-09-06 11:58
28
20
 
29
21
  #### NEW
30
22
 
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- journal-cli (1.0.1)
4
+ journal-cli (1.0.11)
5
5
  chronic (~> 0.10, >= 0.10.2)
6
6
 
7
7
  GEM
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
- def usage
7
- puts "journal v#{Journal::VERSION}"
8
- puts
9
- puts 'Usage: journal [type] [date]'
10
- puts
11
- puts 'Available journal types:'
12
- config = Journal::Checkin.new
13
- puts(config.config['journals'].keys.map { |k| "- #{k}" })
14
- end
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
- if ARGV.count.zero?
17
- puts "No journal specified"
18
- usage
19
- Process.exit 1
20
- end
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 ARGV[0]
23
- when /(-v|--version)/
24
- puts "journal v#{Journal::VERSION}"
25
- Process.exit 0
26
- when /(help|-h|--help)/
27
- usage
28
- Process.exit 0
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 = ARGV.shift
32
-
33
- date = if ARGV.length.positive?
34
- Chronic.parse(ARGV.join(' '), future: false)
35
- else
36
- Time.now
37
- end
38
- checkin = Journal::Checkin.new
39
- if checkin.config['journals'].key?(journal)
40
- checkin.start(journal, date)
41
- checkin.go
42
- else
43
- puts "Journal #{journal} not found"
44
- usage
45
- Process.exit 1
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)
@@ -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 @config['journals'].key? @key
12
+ raise StandardError, "No journal with key #{@key} found" unless Journal.config['journals'].key? @key
19
13
 
20
- @journal = @config['journals'][@key]
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
- results = Data.new(@journal['questions'])
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
- s['questions'].each do |q|
77
- if q['key'] =~ /\./
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
- res[key] = {} unless res.key?(key)
84
- res = res[key]
85
- end
48
+ return unless @journal['markdown']
86
49
 
87
- res[keys.last] = ask_question(q)
88
- else
89
- results[s['key']][:answers][q['key']] = ask_question(q)
90
- end
91
- end
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
- @data = results
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
- if @journal['dayone']
97
- cmd = ['dayone2']
98
- cmd << %(-j "#{@journal['journal']}") if @journal.key?('journal')
99
- cmd << %(-t #{@journal['tags'].join(' ')}) if @journal.key?('tags')
100
- cmd << %(-date "#{@date.strftime('%Y-%m-%d %I:%M %p')}")
101
- `echo #{Shellwords.escape(to_markdown(yaml: false, title: true))} | #{cmd.join(' ')} -- new`
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
- if @journal['markdown']
105
- if @journal['markdown'] =~ /^da(y|ily)/
106
- dir = File.expand_path("~/.local/share/journal/entries/#{@key}")
107
- FileUtils.mkdir_p(dir) unless File.directory?(dir)
108
- filename = "#{@date.strftime('%Y-%m-%d')}.md"
109
- target = File.join(dir, filename)
110
- if File.exist? target
111
- File.open(target, 'a') { |f| f.puts to_markdown(yaml: false, title: true, date: false, time: true) }
112
- else
113
- File.open(target, 'w') { |f| f.puts to_markdown(yaml: true, title: true, date: false, time: true) }
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
- save_data
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
- @journal['sections'].each do |s|
178
- section s['title']
149
+ @sections.each do |key, section|
150
+ answers = section.answers
151
+ section section.title
179
152
 
180
- s['questions'].each do |q|
181
- if q['key'] =~ /\./
182
- res = @data[s['key']][:answers].dup
183
- keys = q['key'].split(/\./)
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(q['prompt'], q['type'], keys.last, res)
162
+ print_answer(question.prompt, question.type, keys.last, res)
190
163
  else
191
- print_answer(q['prompt'], q['type'], q['key'], @data[s['key']][:answers])
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 |k, v|
210
- v[:answers].each do |q, a|
211
- if a.is_a? Hash
212
- output[q] = {}
213
- a.each do |key, value|
214
- output[q][key] = case value.class.to_s
215
- when /Weather/
216
- { 'high' => value.data[:high], 'low' => value.data[:low], 'condition' => value.data[:condition] }
217
- else
218
- value
219
- end
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[q] = a
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
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Journal
4
+ class Sections < Hash
5
+ def initialize(sections)
6
+ sections.each do |sect|
7
+ section = Section.new(sect)
8
+ self[section.key] = section
9
+ end
10
+ super
11
+ end
12
+ end
13
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Journal
4
- VERSION = '1.0.9'
4
+ VERSION = '1.0.11'
5
5
  end
data/lib/journal-cli.rb CHANGED
@@ -7,7 +7,52 @@ require 'yaml'
7
7
  require 'chronic'
8
8
  require 'fileutils'
9
9
 
10
- require_relative "journal-cli/version"
11
- require_relative "journal-cli/data"
12
- require_relative "journal-cli/weather"
13
- require_relative "journal-cli/checkin"
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
+ unless File.exist?(config)
25
+ default_config = {
26
+ 'weather_api' => 'XXXXXXXXXXXXXXXXXx',
27
+ 'zip' => 'XXXXX',
28
+ 'journals' => {
29
+ 'demo' => {
30
+ 'dayone' => false,
31
+ 'markdown' => 'single',
32
+ 'title' => '5-minute checkin',
33
+ 'sections' => [
34
+ { 'title' => 'Quick checkin',
35
+ 'key' => 'checkin',
36
+ 'questions' => [
37
+ { 'prompt' => 'What\'s happening?', 'key' => 'journal', 'type' => 'multiline' }
38
+ ] }
39
+ ]
40
+ }
41
+ }
42
+ }
43
+ File.open(config, 'w') { |f| f.puts(YAML.dump(default_config)) }
44
+ puts "New configuration written to #{config}, please edit."
45
+ Process.exit 0
46
+ end
47
+ @config = YAML.load(IO.read(config))
48
+
49
+ if @config['journals'].key?('demo')
50
+ puts "Demo journal detected, please edit the configuration file at #{config}"
51
+ Process.exit 1
52
+ end
53
+ end
54
+
55
+ @config
56
+ end
57
+ end
58
+ 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.9
4
+ version: 1.0.11
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