journal-cli 1.0.22 → 1.0.23

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
  SHA256:
3
- metadata.gz: 1255e03e2644a0bb96f72622c8815595f41bec61e1add52529b697097f4b94f6
4
- data.tar.gz: 613eca7fbaccd6536b3edd23da7160c337ad1bf7dc7dc509b41ddf85e788c478
3
+ metadata.gz: 94254a744cbef7c84b89dc49f3811a641e5ece9b81e813cef5085c6111673846
4
+ data.tar.gz: 06d736bceebf43d0505ce2f003a004a1dffc508d678f20ff1f1d8d2e06a51390
5
5
  SHA512:
6
- metadata.gz: 34c25cc5c7c076f47dfa2fedd6bd7434dc8b7268b2662cef74bdcabbd6fdbe99b1a3882ad4c129e6c5434b169fd0d5a377bbeef78207e993b026125339386a96
7
- data.tar.gz: 3a1fccc6120ed77cc602a1448a9949b49aa42ea658d3c93d11de7d77aad9a6bc0e707ac125f0faaa93bad5bb3de2b921fe35f57afd1a112a01982ce5bc9b01b6
6
+ metadata.gz: 827d6165ddbcfb7752d0b91022b0c7779af14280503f915f007c1b3e937c4b6c989bdf0167b1d7399a0a2aaa9829528203784f80888c2ec9801d2ee614d653de
7
+ data.tar.gz: 5fb214409b54da6c11321bf0c6f77eb4221f54f0803474787afee2f696930fe6d025af8e8915cf9a0759cc4e50d9463d4e6d15c6e7fd271f24c01c385f2170e8
data/CHANGELOG.md CHANGED
@@ -1,3 +1,16 @@
1
+ ### 1.0.23
2
+
3
+ 2023-09-20 08:30
4
+
5
+ #### NEW
6
+
7
+ - Question types weather.forecast and weather.current allow more specific weather entry types
8
+ - Time-based conditions for questions and sections (`condition: before noon` or `condition: < 12pm`)
9
+
10
+ #### FIXED
11
+
12
+ - Test for existence of dayone2 binary before attempting to write a Day One entry, provide error message
13
+
1
14
  ### 1.0.22
2
15
 
3
16
  2023-09-18 10:23
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- journal-cli (1.0.21)
4
+ journal-cli (1.0.23)
5
5
  chronic (~> 0.10, >= 0.10.2)
6
6
  tty-reader (~> 0.9, >= 0.9.0)
7
7
  tty-which (~> 0.5, >= 0.5.0)
data/README.md CHANGED
@@ -52,6 +52,10 @@ This file contains a YAML definition of your journal. Each journal gets a top-le
52
52
 
53
53
  You can include weather data automatically by setting a question type to 'weather'. In order for this to work, you'll need to define `zip` and `weather_api` keys. `zip` is just your zip code, and `weather_api` is a key from WeatherAPI.com. Sign up [here](https://www.weatherapi.com/) for a free plan, and then visit the [profile page](https://www.weatherapi.com/my/) to see your API key at the top.
54
54
 
55
+ If a question type is set to `weather.forecast`, only the predicted condition, high, and low will be included in the JSON data for the question. A full printout of hourly temps will be included in the Markdown/Day One output.
56
+
57
+ If the question type is `weather.current`, only the current condition and temperature will be recorded to the JSON, and a string containing "[TEMP] and [CONDITION]" (e.g. "64 and Sunny") will be recorded to Markdown/Day One for the question.
58
+
55
59
  ### Journal Configuration
56
60
 
57
61
  Edit the file at `~/.config/journal/journals.yaml` following this structure:
@@ -96,9 +100,12 @@ journals: # required key
96
100
  - title: Weather # Title of the section (will create template sections in Day One)
97
101
  key: weather # the key to use in the structured data, will contain all of the answers
98
102
  questions: # required key
99
- - prompt: Current weather # The prompt shown on the command line, will also become a header in the journal entries (Markdown, Day One)
103
+ - prompt: Current Weather
104
+ key: weather.current
105
+ type: weather.current
106
+ - prompt: Weather Forecast # The prompt shown on the command line, will also become a header in the journal entries (Markdown, Day One)
100
107
  key: weather.forecast # if a key contains a dot, it will create nested data, e.g. `{ 'weather': { 'forecast': data } }`
101
- type: weather # Set this to weather for weather data
108
+ type: weather.forecast # Set this to weather for weather data
102
109
  - title: Health # New section
103
110
  key: health
104
111
  questions:
@@ -141,10 +148,18 @@ A question `type` can be one of:
141
148
  - `text` or `string` will request a single-line string, submitted on return
142
149
  - `multiline` for multiline strings (opens a readline editor, use ctrl-d to save)
143
150
  - `weather` will just insert current weather data with no prompt
151
+ * `weather.forecast` will insert just the forecast
152
+ * `weather.current` will insert just the current temperature and condition
144
153
  - `number` or `float` will request numeric input, stored as a float (decimal)
145
154
  - `integer` will convert numeric input to the nearest integer
146
155
  - `date` will request a natural language date which will be parsed into a date object
147
156
 
157
+ ### Conditional Questions
158
+
159
+ You can have a question only show up based on conditions. Currently the only condition is time based. Just add a key called `condition` to the question definition, then include a natural language string like `before noon` or `after 3pm`. If the condition is matched, then the question will be displayed, otherwise it will be skipped and its data entry in the JSON will be null.
160
+
161
+ Conditions can be applied to individual questions, or to entire sections, depending on where the `condition` key is placed.
162
+
148
163
  ### Naming Keys
149
164
 
150
165
  If you want data stored in a nested object, you can set a question type to `dictionary` and set the prompt to `null` (or just leave the key out), but give it a key that will serve as the parent in the object. Then in the nested questions, give them a key in the dot format `[PARENT_KEY].[CHILD_KEY]`. Section keys automatically nest their questions, but if you want to go deeper, you could have a question with the key `health` and type `dictionary`, then have questions with keys like `health.rating` and `health.notes`. If the section key was `status`, the resulting dictionary would look like this in the JSON:
data/bin/journal CHANGED
@@ -4,6 +4,8 @@ $LOAD_PATH.unshift File.join(__dir__, '..', 'lib')
4
4
  require 'journal-cli'
5
5
  require 'optparse'
6
6
 
7
+ trap('SIGINT') { exit! }
8
+
7
9
  module Journal
8
10
  class << self
9
11
  def usage
@@ -33,8 +35,10 @@ module Journal
33
35
  Time.now
34
36
  end
35
37
 
38
+ Journal.date = date
39
+
36
40
  if Journal.config['journals'].key?(journal)
37
- checkin = Journal::Checkin.new(journal, date)
41
+ checkin = Journal::Checkin.new(journal)
38
42
  checkin.go
39
43
  else
40
44
  puts "Journal #{journal} not found"
@@ -3,10 +3,10 @@ module Journal
3
3
  class Checkin
4
4
  attr_reader :key, :date, :data, :config, :journal, :sections, :title, :output
5
5
 
6
- def initialize(journal, date)
6
+ def initialize(journal)
7
7
  @key = journal
8
8
  @output = []
9
- @date = date
9
+ @date = Journal.date
10
10
  @date.localtime
11
11
 
12
12
  raise StandardError, "No journal with key #{@key} found" unless Journal.config['journals'].key? @key
@@ -36,7 +36,7 @@ module Journal
36
36
  end
37
37
 
38
38
  def hr
39
- @output << "\n---\n"
39
+ @output << "\n* * * * * *\n"
40
40
  end
41
41
 
42
42
  def go
@@ -58,6 +58,11 @@ module Journal
58
58
  end
59
59
 
60
60
  def save_day_one_entry
61
+ unless TTY::Which.exist?('dayone2')
62
+ Journal.notify('{br}Day One CLI not installed, no Day One entry created')
63
+ return
64
+ end
65
+ @date.localtime
61
66
  cmd = ['dayone2']
62
67
  cmd << %(-j "#{@journal['journal']}") if @journal.key?('journal')
63
68
  cmd << %(-t #{@journal['tags'].join(' ')}) if @journal.key?('tags')
@@ -128,11 +133,17 @@ module Journal
128
133
  end
129
134
 
130
135
  def print_answer(prompt, type, key, data)
136
+ return if data.nil? || !data.key?(key)
137
+
131
138
  case type
132
139
  when /^(weather|forecast)/
133
140
  header prompt
134
- @output << data[key].to_markdown
135
- hr
141
+ @output << case type
142
+ when /current$/
143
+ data[key].current
144
+ else
145
+ data[key].to_markdown
146
+ end
136
147
  when /^(int|num)/
137
148
  @output << "#{prompt}: #{data[key]} " unless data[key].nil?
138
149
  when /^date/
@@ -158,7 +169,14 @@ module Journal
158
169
  v.localtime
159
170
  data[k] = v.strftime('%Y-%m-%d %H:%M')
160
171
  when /Weather/
161
- data[k] = v.to_s
172
+ data[k] = case k
173
+ when /current$/
174
+ v.current
175
+ when /forecast$/
176
+ data[k] = v.forecast
177
+ else
178
+ data[k] = v.to_s
179
+ end
162
180
  else
163
181
  data[k] = v
164
182
  end
@@ -240,11 +258,18 @@ module Journal
240
258
  v.each do |key, value|
241
259
  result = case value.class.to_s
242
260
  when /Weather/
243
- {
244
- 'high' => value.data[:high],
245
- 'low' => value.data[:low],
246
- 'condition' => value.data[:condition]
247
- }
261
+ if key =~ /current$/
262
+ {
263
+ 'temp' => value.data[:temp],
264
+ 'condition' => value.data[:current_condition]
265
+ }
266
+ else
267
+ {
268
+ 'high' => value.data[:high],
269
+ 'low' => value.data[:low],
270
+ 'condition' => value.data[:condition]
271
+ }
272
+ end
248
273
  else
249
274
  value
250
275
  end
@@ -3,7 +3,7 @@
3
3
  module Journal
4
4
  # Individual question
5
5
  class Question
6
- attr_reader :key, :type, :min, :max, :prompt, :secondary_prompt, :gum
6
+ attr_reader :key, :type, :min, :max, :prompt, :secondary_prompt, :gum, :condition
7
7
 
8
8
  ##
9
9
  ## Initializes the given question.
@@ -20,6 +20,7 @@ module Journal
20
20
  @prompt = question['prompt'] || nil
21
21
  @secondary_prompt = question['secondary_prompt'] || nil
22
22
  @gum = TTY::Which.exist?('gum')
23
+ @condition = question.key?('condition') ? question['condition'].parse_condition : true
23
24
  end
24
25
 
25
26
  ##
@@ -27,9 +28,11 @@ module Journal
27
28
  ##
28
29
  ## @return [Number, String] the response based on @type
29
30
  ##
30
- def ask
31
+ def ask(condition)
31
32
  return nil if @prompt.nil?
32
33
 
34
+ return nil unless @condition && condition
35
+
33
36
  case @type
34
37
  when /^int/i
35
38
  read_number(integer: true)
@@ -126,6 +129,7 @@ module Journal
126
129
  ##
127
130
  ##
128
131
  def read_number_gum
132
+ trap('SIGINT') { exit! }
129
133
  res = `gum input --placeholder "#{@min}-#{@max}"`.strip
130
134
  return nil if res.strip.empty?
131
135
 
@@ -140,6 +144,7 @@ module Journal
140
144
  ## @return [Number] integer response
141
145
  ##
142
146
  def read_line_tty
147
+ trap('SIGINT') { exit! }
143
148
  reader = TTY::Reader.new
144
149
  res = reader.read_line('>> ')
145
150
  return nil if res.strip.empty?
@@ -155,6 +160,7 @@ module Journal
155
160
  ## @return [Number] integer response
156
161
  ##
157
162
  def read_line_gum(prompt)
163
+ trap('SIGINT') { exit! }
158
164
  `gum input --placeholder "#{prompt} (blank to end answer)"`
159
165
  end
160
166
 
@@ -164,6 +170,7 @@ module Journal
164
170
  ## @return [string] multiline input
165
171
  ##
166
172
  def read_mutliline_tty
173
+ trap('SIGINT') { exit! }
167
174
  reader = TTY::Reader.new
168
175
  res = reader.read_multiline
169
176
  res.join("\n")
@@ -175,6 +182,7 @@ module Journal
175
182
  ## @return [string] multiline input
176
183
  ##
177
184
  def read_multiline_gum(prompt)
185
+ trap('SIGINT') { exit! }
178
186
  `gum write --placeholder "#{prompt}" --width 80 --char-limit 0`
179
187
  end
180
188
  end
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Journal
4
4
  class Section
5
- attr_accessor :key, :title, :questions, :answers
5
+ attr_accessor :key, :title, :questions, :answers, :condition
6
6
 
7
7
  ##
8
8
  ## Initializes the given section.
@@ -15,6 +15,7 @@ module Journal
15
15
  def initialize(section)
16
16
  @key = section['key']
17
17
  @title = section['title']
18
+ @condition = section.key?('condition') ? section['condition'].parse_condition : true
18
19
  @questions = section['questions'].map { |question| Question.new(question) }
19
20
  @questions.delete_if { |q| q.prompt.nil? }
20
21
  @answers = {}
@@ -38,9 +39,9 @@ module Journal
38
39
  res = res[key]
39
40
  end
40
41
 
41
- res[keys.last] = question.ask
42
+ res[keys.last] = question.ask(@condition)
42
43
  else
43
- @answers[question.key] = question.ask
44
+ @answers[question.key] = question.ask(@condition)
44
45
  end
45
46
  end
46
47
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Journal
4
- VERSION = '1.0.22'
4
+ VERSION = '1.0.23'
5
5
  end
@@ -54,6 +54,14 @@ module Journal
54
54
  }
55
55
  end
56
56
 
57
+ def current
58
+ "#{@data[:temp]} and #{@data[:current_condition]}"
59
+ end
60
+
61
+ def forecast
62
+ "#{@data[:condition]} #{@data[:high]}/#{@data[:low]}"
63
+ end
64
+
57
65
  def to_s
58
66
  "#{@data[:temp].round} and #{@data[:current_condition]} (#{@data[:high].round}/#{@data[:low].round})"
59
67
  end
@@ -61,8 +69,8 @@ module Journal
61
69
  def to_markdown
62
70
  output = []
63
71
 
64
- output << "Forecast for #{@data[:day]}: #{@data[:condition]} #{@data[:high]}/#{@data[:low]} "
65
- output << "Currently: #{@data[:temp]} and #{@data[:current_condition]}"
72
+ output << "Forecast for #{@data[:day]}: #{forecast} "
73
+ output << "Currently: #{current}"
66
74
  output << ''
67
75
 
68
76
  # Hours
data/lib/journal-cli.rb CHANGED
@@ -11,6 +11,7 @@ require 'tty-which'
11
11
  require 'tty-reader'
12
12
  require_relative 'journal-cli/version'
13
13
  require_relative 'journal-cli/color'
14
+ require_relative 'journal-cli/string'
14
15
  require_relative 'journal-cli/data'
15
16
  require_relative 'journal-cli/weather'
16
17
  require_relative 'journal-cli/checkin'
@@ -21,6 +22,8 @@ require_relative 'journal-cli/question'
21
22
  # Main Journal module
22
23
  module Journal
23
24
  class << self
25
+ attr_accessor :date
26
+
24
27
  def notify(string, debug: false, exit_code: nil)
25
28
  if debug
26
29
  $stderr.puts "{dw}#{string}{x}".x
data/src/_README.md CHANGED
@@ -55,6 +55,10 @@ This file contains a YAML definition of your journal. Each journal gets a top-le
55
55
 
56
56
  You can include weather data automatically by setting a question type to 'weather'. In order for this to work, you'll need to define `zip` and `weather_api` keys. `zip` is just your zip code, and `weather_api` is a key from WeatherAPI.com. Sign up [here](https://www.weatherapi.com/) for a free plan, and then visit the [profile page](https://www.weatherapi.com/my/) to see your API key at the top.
57
57
 
58
+ If a question type is set to `weather.forecast`, only the predicted condition, high, and low will be included in the JSON data for the question. A full printout of hourly temps will be included in the Markdown/Day One output.
59
+
60
+ If the question type is `weather.current`, only the current condition and temperature will be recorded to the JSON, and a string containing "[TEMP] and [CONDITION]" (e.g. "64 and Sunny") will be recorded to Markdown/Day One for the question.
61
+
58
62
  ### Journal Configuration
59
63
 
60
64
  Edit the file at `~/.config/journal/journals.yaml` following this structure:
@@ -99,9 +103,12 @@ journals: # required key
99
103
  - title: Weather # Title of the section (will create template sections in Day One)
100
104
  key: weather # the key to use in the structured data, will contain all of the answers
101
105
  questions: # required key
102
- - prompt: Current weather # The prompt shown on the command line, will also become a header in the journal entries (Markdown, Day One)
106
+ - prompt: Current Weather
107
+ key: weather.current
108
+ type: weather.current
109
+ - prompt: Weather Forecast # The prompt shown on the command line, will also become a header in the journal entries (Markdown, Day One)
103
110
  key: weather.forecast # if a key contains a dot, it will create nested data, e.g. `{ 'weather': { 'forecast': data } }`
104
- type: weather # Set this to weather for weather data
111
+ type: weather.forecast # Set this to weather for weather data
105
112
  - title: Health # New section
106
113
  key: health
107
114
  questions:
@@ -144,10 +151,18 @@ A question `type` can be one of:
144
151
  - `text` or `string` will request a single-line string, submitted on return
145
152
  - `multiline` for multiline strings (opens a readline editor, use ctrl-d to save)
146
153
  - `weather` will just insert current weather data with no prompt
154
+ * `weather.forecast` will insert just the forecast
155
+ * `weather.current` will insert just the current temperature and condition
147
156
  - `number` or `float` will request numeric input, stored as a float (decimal)
148
157
  - `integer` will convert numeric input to the nearest integer
149
158
  - `date` will request a natural language date which will be parsed into a date object
150
159
 
160
+ ### Conditional Questions
161
+
162
+ You can have a question only show up based on conditions. Currently the only condition is time based. Just add a key called `condition` to the question definition, then include a natural language string like `before noon` or `after 3pm`. If the condition is matched, then the question will be displayed, otherwise it will be skipped and its data entry in the JSON will be null.
163
+
164
+ Conditions can be applied to individual questions, or to entire sections, depending on where the `condition` key is placed.
165
+
151
166
  ### Naming Keys
152
167
 
153
168
  If you want data stored in a nested object, you can set a question type to `dictionary` and set the prompt to `null` (or just leave the key out), but give it a key that will serve as the parent in the object. Then in the nested questions, give them a key in the dot format `[PARENT_KEY].[CHILD_KEY]`. Section keys automatically nest their questions, but if you want to go deeper, you could have a question with the key `health` and type `dictionary`, then have questions with keys like `health.rating` and `health.notes`. If the section key was `status`, the resulting dictionary would look like this in the JSON:
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: journal-cli
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.22
4
+ version: 1.0.23
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brett Terpstra
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-09-18 00:00:00.000000000 Z
11
+ date: 2023-09-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: tty-which