morning-pages-journal 2.0.0
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.
- data/.gitignore +5 -0
- data/.rspec +2 -0
- data/Gemfile +4 -0
- data/README.md +70 -0
- data/Rakefile +1 -0
- data/bin/mp +58 -0
- data/lib/morning-pages-journal.rb +6 -0
- data/lib/morning-pages-journal/journal.rb +236 -0
- data/lib/morning-pages-journal/version.rb +7 -0
- data/morning-pages-journal.gemspec +28 -0
- data/spec/morning-pages-journal/page_spec.rb +5 -0
- data/spec/spec_helper.rb +17 -0
- metadata +109 -0
data/.rspec
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
Morning Pages Journal
|
2
|
+
=====================
|
3
|
+
|
4
|
+
A command line tool to manage morning pages.
|
5
|
+
|
6
|
+
Morning Pages are three pages of longhand, stream of consciousness writing,
|
7
|
+
done first thing in the morning. *There is no wrong way to do Morning Pages*–
|
8
|
+
they are not high art. They are not even “writing.” They are about
|
9
|
+
anything and everything that crosses your mind– and they are for your eyes
|
10
|
+
only. Morning Pages provoke, clarify, comfort, cajole, prioritize and
|
11
|
+
synchronize the day at hand. Do not over-think Morning Pages: just put
|
12
|
+
three pages of anything on the page…and then do three more pages tomorrow.
|
13
|
+
|
14
|
+
I thought I had a great idea. I wrote the code, then I found out somebody else did it. Anyway, here is my code...
|
15
|
+
|
16
|
+
Usage
|
17
|
+
-----
|
18
|
+
|
19
|
+
### To open current day morning page in editor:
|
20
|
+
|
21
|
+
$ mp
|
22
|
+
|
23
|
+
### To list morning pages and progress:
|
24
|
+
|
25
|
+
$ mp list # current month
|
26
|
+
$ mp list -w # current week
|
27
|
+
$ mp list -d # curent day
|
28
|
+
$ mp list -m # current month
|
29
|
+
$ mp list -y # current year
|
30
|
+
|
31
|
+
### To get stats:
|
32
|
+
|
33
|
+
$ mp stat # current month
|
34
|
+
$ mp stat -w # current week
|
35
|
+
$ mp stat -d # curent day
|
36
|
+
$ mp stat -m # current month
|
37
|
+
$ mp stat -y # current year
|
38
|
+
|
39
|
+
### To count words:
|
40
|
+
|
41
|
+
$ mp words # current month
|
42
|
+
$ mp words -w # current week
|
43
|
+
$ mp words -d # curent day
|
44
|
+
$ mp words -m # current month
|
45
|
+
$ mp words -y # current year
|
46
|
+
|
47
|
+
Configuration
|
48
|
+
-------------
|
49
|
+
|
50
|
+
A `~/.mp.yml` file will be created that looks like
|
51
|
+
|
52
|
+
editor: mate
|
53
|
+
folder: ~/.morning-pages/
|
54
|
+
words: 750
|
55
|
+
stats: 50
|
56
|
+
|
57
|
+
You can change setting manually or use
|
58
|
+
|
59
|
+
mp config <key> <value>
|
60
|
+
mp config editor vi
|
61
|
+
|
62
|
+
You can also specify a config file and run any of the commands
|
63
|
+
|
64
|
+
mp -c custom.yaml list
|
65
|
+
|
66
|
+
|
67
|
+
Installation
|
68
|
+
------------
|
69
|
+
|
70
|
+
gem install morning-pages-journal
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/bin/mp
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
$: << File.dirname(__FILE__) + '/../lib'
|
3
|
+
|
4
|
+
require 'trollop'
|
5
|
+
require 'morning-pages-journal'
|
6
|
+
require "yaml"
|
7
|
+
|
8
|
+
def range(sub_opts)
|
9
|
+
range = (sub_opts[:day] && :day) || (sub_opts[:week] && :week) || (sub_opts[:month] && :month) || (sub_opts[:year] && :year) || :month
|
10
|
+
end
|
11
|
+
|
12
|
+
SUB_COMMANDS = %w(list stat words config)
|
13
|
+
opts = Trollop.options do
|
14
|
+
banner "Usage: mp [options] [list | stat | words] [options]"
|
15
|
+
opt :config,"Configuration file", :required => false, :type => :string, :default => "~/.mp.yml"
|
16
|
+
stop_on SUB_COMMANDS
|
17
|
+
end
|
18
|
+
|
19
|
+
cli = MorningPagesJournal::CLI.new(opts)
|
20
|
+
|
21
|
+
if ARGV.empty?
|
22
|
+
cli.open
|
23
|
+
else
|
24
|
+
cmd = ARGV.shift # get the subcomman
|
25
|
+
|
26
|
+
def parse_options
|
27
|
+
Trollop.options do
|
28
|
+
opt :day,"Show only for the day", :required => false, :default => false
|
29
|
+
opt :week,"Show only for the week", :required => false , :default => false
|
30
|
+
opt :month,"Show only for the month", :required => false, :default => false
|
31
|
+
opt :year,"Show only for the year", :required => false, :default => false
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
case cmd
|
36
|
+
when "list"
|
37
|
+
sub_opts = parse_options
|
38
|
+
|
39
|
+
cli.list(:range => range(sub_opts))
|
40
|
+
when "stat"
|
41
|
+
sub_opts = parse_options
|
42
|
+
|
43
|
+
cli.stat(:range => range(sub_opts))
|
44
|
+
when "words"
|
45
|
+
sub_opts = parse_options
|
46
|
+
|
47
|
+
cli.words(:range => range(sub_opts))
|
48
|
+
when "config"
|
49
|
+
raise Trollop::die("config requires 2 arguments key and value") if ARGV.size != 2
|
50
|
+
key = ARGV.shift
|
51
|
+
value = ARGV.shift
|
52
|
+
|
53
|
+
cli.update_config(key, value)
|
54
|
+
else
|
55
|
+
puts "Unknown command '#{cmd}'".color(:red)
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
@@ -0,0 +1,236 @@
|
|
1
|
+
require 'date'
|
2
|
+
require 'rainbow'
|
3
|
+
|
4
|
+
module MorningPagesJournal
|
5
|
+
|
6
|
+
class Page
|
7
|
+
attr_reader :file_path
|
8
|
+
|
9
|
+
def initialize(file_path)
|
10
|
+
@file_path = file_path
|
11
|
+
end
|
12
|
+
|
13
|
+
def date
|
14
|
+
return @date if @date
|
15
|
+
|
16
|
+
s = @file_path.split("/")
|
17
|
+
|
18
|
+
year_month = s[s.size-2]
|
19
|
+
day = s[s.size-1].split(".")[0]
|
20
|
+
|
21
|
+
@date = Date.parse("#{year_month}-#{day}")
|
22
|
+
@date
|
23
|
+
end
|
24
|
+
|
25
|
+
def words
|
26
|
+
@count ||= `wc -w #{@file_path}`.split(" ")[0]
|
27
|
+
end
|
28
|
+
|
29
|
+
def word_count(hash = Hash.new(0))
|
30
|
+
content.split.inject(hash) { |h,v| h[v] += 1; h }
|
31
|
+
end
|
32
|
+
|
33
|
+
def content
|
34
|
+
File.open(@file_path).read
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
class Journal
|
40
|
+
|
41
|
+
def initialize(options)
|
42
|
+
raise "Base folder is required" unless options[:base_folder]
|
43
|
+
@base_folder = options[:base_folder]
|
44
|
+
end
|
45
|
+
|
46
|
+
def today_folder
|
47
|
+
folder = Date.today.strftime("%Y-%m")
|
48
|
+
File.join(@base_folder,folder)
|
49
|
+
end
|
50
|
+
|
51
|
+
def today_file
|
52
|
+
file_name = Date.today.strftime("%d")
|
53
|
+
File.join(today_folder,"#{file_name}.txt")
|
54
|
+
end
|
55
|
+
|
56
|
+
def pages
|
57
|
+
@pages ||= pages_files.collect { |path| Page.new(path) }.sort { |a, b| a.date <=> a.date }
|
58
|
+
end
|
59
|
+
|
60
|
+
def get_page(date)
|
61
|
+
@pages.select {|p| p.date == date }.first
|
62
|
+
end
|
63
|
+
|
64
|
+
def each_day(range = :month)
|
65
|
+
return if pages.empty?
|
66
|
+
max = pages.last.date
|
67
|
+
min = date_starting_at(max, range)
|
68
|
+
|
69
|
+
min.upto(max).each do |date|
|
70
|
+
yield date
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def min_date(range = :month)
|
75
|
+
# pages.first.date
|
76
|
+
date_starting_at(max_date,range)
|
77
|
+
end
|
78
|
+
|
79
|
+
def max_date
|
80
|
+
pages.last.date
|
81
|
+
end
|
82
|
+
|
83
|
+
def word_count(range=:month)
|
84
|
+
hash = Hash.new(0)
|
85
|
+
pages_from(min_date(range),max_date).each do |p|
|
86
|
+
p.word_count(hash)
|
87
|
+
end
|
88
|
+
hash
|
89
|
+
end
|
90
|
+
|
91
|
+
def average_words
|
92
|
+
w = pages.collect {|p| p.words.to_i}
|
93
|
+
w.inject(0.0) { |sum, el| sum + el } / w.size
|
94
|
+
end
|
95
|
+
|
96
|
+
def pages_from(from,to)
|
97
|
+
pages.select do |p|
|
98
|
+
p.date >= from && p.date <= to
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
private
|
103
|
+
|
104
|
+
def pages_files
|
105
|
+
Dir.glob("#{File.expand_path(@base_folder)}/**/*").reject {|fn| File.directory?(fn) }
|
106
|
+
end
|
107
|
+
|
108
|
+
def date_starting_at(date,range)
|
109
|
+
case range
|
110
|
+
when :day then date
|
111
|
+
when :week then date - (date.wday-1)
|
112
|
+
when :month then date - (date.mday-1)
|
113
|
+
when :year then date - (date.yday-1)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
class CLI
|
119
|
+
|
120
|
+
def initialize(command_line_arguments)
|
121
|
+
@opts = command_line_arguments
|
122
|
+
@opts[:config] = File.expand_path(@opts[:config])
|
123
|
+
end
|
124
|
+
|
125
|
+
def opts
|
126
|
+
@opts
|
127
|
+
end
|
128
|
+
|
129
|
+
def config
|
130
|
+
create_config_if_not_exists!
|
131
|
+
|
132
|
+
@config ||= YAML::load(File.open(opts[:config]))
|
133
|
+
end
|
134
|
+
|
135
|
+
|
136
|
+
def config_words
|
137
|
+
config["words"] || 750
|
138
|
+
end
|
139
|
+
|
140
|
+
def stats_words
|
141
|
+
(config["stats"] || 50).to_i
|
142
|
+
end
|
143
|
+
|
144
|
+
def open
|
145
|
+
journal = MorningPagesJournal::Journal.new(:base_folder => config["folder"])
|
146
|
+
editor = config["editor"]
|
147
|
+
|
148
|
+
system "mkdir -p #{journal.today_folder} ; #{editor} #{journal.today_file}"
|
149
|
+
end
|
150
|
+
|
151
|
+
def list(options)
|
152
|
+
journal = MorningPagesJournal::Journal.new(:base_folder => config["folder"])
|
153
|
+
|
154
|
+
month_name = ""
|
155
|
+
total_words = 0
|
156
|
+
journal.each_day(options[:range]) do |date|
|
157
|
+
if month_name != date.strftime("%B")
|
158
|
+
month_name = date.strftime("%B")
|
159
|
+
puts month_name
|
160
|
+
puts "-" * 100
|
161
|
+
end
|
162
|
+
|
163
|
+
page = journal.get_page(date)
|
164
|
+
|
165
|
+
words,color = if page
|
166
|
+
if page.words.to_i < config_words
|
167
|
+
[page.words.to_i, :red]
|
168
|
+
else
|
169
|
+
[page.words.to_i, :green]
|
170
|
+
end
|
171
|
+
else
|
172
|
+
[0,:yellow]
|
173
|
+
end
|
174
|
+
|
175
|
+
total_words += words
|
176
|
+
puts "#{date.strftime('%a, %d')}\t#{words.to_s.color(color)}\t" + ("="* (words/10).to_i).color(color)
|
177
|
+
|
178
|
+
if date.strftime('%a') == "Sat"
|
179
|
+
puts ""
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
def stat(options)
|
185
|
+
journal = MorningPagesJournal::Journal.new(:base_folder => config["folder"])
|
186
|
+
|
187
|
+
min_date = journal.min_date(options[:range])
|
188
|
+
days = ((journal.max_date+1) - min_date).to_i
|
189
|
+
morning_pages = journal.pages_from(min_date,journal.max_date).size
|
190
|
+
missed = days - morning_pages
|
191
|
+
|
192
|
+
puts "Average Words:\t#{journal.average_words.to_i}\n"
|
193
|
+
puts "From:\t#{min_date}"
|
194
|
+
puts "To:\t#{journal.max_date}"
|
195
|
+
puts "Total days:\t#{days}"
|
196
|
+
puts "Morning pages:\t#{morning_pages}"
|
197
|
+
puts "Missed:\t#{missed}"
|
198
|
+
puts "\n"
|
199
|
+
end
|
200
|
+
|
201
|
+
def words(options)
|
202
|
+
journal = MorningPagesJournal::Journal.new(:base_folder => config["folder"])
|
203
|
+
journal.word_count(options[:range]).sort_by {|k,v| v}.reverse.take(stats_words).each do |e|
|
204
|
+
puts "#{e[0]}\t#{e[1]}"
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
def update_config(key,value)
|
209
|
+
c = config
|
210
|
+
c[key] = value
|
211
|
+
|
212
|
+
File.open(opts[:config],"w+") do |f|
|
213
|
+
f.write YAML::dump(c)
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
private
|
218
|
+
|
219
|
+
def create_config_if_not_exists!
|
220
|
+
unless File.exists?(opts[:config])
|
221
|
+
File.open(opts[:config],"w+") do |f|
|
222
|
+
f.write YAML::dump({
|
223
|
+
"editor" => "mate",
|
224
|
+
"folder" => "~/.morning-pages/",
|
225
|
+
"words" => 750,
|
226
|
+
"stats" => 50
|
227
|
+
})
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
end
|
232
|
+
|
233
|
+
end
|
234
|
+
|
235
|
+
|
236
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "morning-pages-journal/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "morning-pages-journal"
|
7
|
+
s.version = Morning::Pages::Journal::VERSION
|
8
|
+
s.authors = ["Federico Dayan"]
|
9
|
+
s.email = ["federico.dayan@gmail.com"]
|
10
|
+
s.homepage = ""
|
11
|
+
s.summary = %q{Command line tool to manage morning pages}
|
12
|
+
s.description = %q{Morning pages are three pages of writing done every day. This tool organizes pages and keep track of progress. It does not share anything of course }
|
13
|
+
|
14
|
+
s.rubyforge_project = "morning-pages-journal"
|
15
|
+
|
16
|
+
s.files = `git ls-files`.split("\n")
|
17
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
|
+
s.require_paths = ["lib"]
|
20
|
+
|
21
|
+
# specify any dependencies here; for example:
|
22
|
+
# s.add_development_dependency "rspec"
|
23
|
+
# s.add_runtime_dependency "rest-client"
|
24
|
+
|
25
|
+
s.add_dependency 'trollop'
|
26
|
+
s.add_dependency 'rainbow'
|
27
|
+
s.add_development_dependency 'rspec'
|
28
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
# This file was generated by the `rspec --init` command. Conventionally, all
|
2
|
+
# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
|
3
|
+
# Require this file using `require "spec_helper"` to ensure that it is only
|
4
|
+
# loaded once.
|
5
|
+
#
|
6
|
+
# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
|
7
|
+
RSpec.configure do |config|
|
8
|
+
config.treat_symbols_as_metadata_keys_with_true_values = true
|
9
|
+
config.run_all_when_everything_filtered = true
|
10
|
+
config.filter_run :focus
|
11
|
+
|
12
|
+
# Run specs in random order to surface order dependencies. If you find an
|
13
|
+
# order dependency and want to debug it, you can fix the order by providing
|
14
|
+
# the seed, which is printed after each run.
|
15
|
+
# --seed 1234
|
16
|
+
config.order = 'random'
|
17
|
+
end
|
metadata
ADDED
@@ -0,0 +1,109 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: morning-pages-journal
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 2.0.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Federico Dayan
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-02-13 00:00:00.000000000Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: trollop
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: rainbow
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: rspec
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
description: ! 'Morning pages are three pages of writing done every day. This tool
|
63
|
+
organizes pages and keep track of progress. It does not share anything of course '
|
64
|
+
email:
|
65
|
+
- federico.dayan@gmail.com
|
66
|
+
executables:
|
67
|
+
- mp
|
68
|
+
extensions: []
|
69
|
+
extra_rdoc_files: []
|
70
|
+
files:
|
71
|
+
- .gitignore
|
72
|
+
- .rspec
|
73
|
+
- Gemfile
|
74
|
+
- README.md
|
75
|
+
- Rakefile
|
76
|
+
- bin/mp
|
77
|
+
- lib/morning-pages-journal.rb
|
78
|
+
- lib/morning-pages-journal/journal.rb
|
79
|
+
- lib/morning-pages-journal/version.rb
|
80
|
+
- morning-pages-journal.gemspec
|
81
|
+
- spec/morning-pages-journal/page_spec.rb
|
82
|
+
- spec/spec_helper.rb
|
83
|
+
homepage: ''
|
84
|
+
licenses: []
|
85
|
+
post_install_message:
|
86
|
+
rdoc_options: []
|
87
|
+
require_paths:
|
88
|
+
- lib
|
89
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
90
|
+
none: false
|
91
|
+
requirements:
|
92
|
+
- - ! '>='
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
version: '0'
|
95
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
96
|
+
none: false
|
97
|
+
requirements:
|
98
|
+
- - ! '>='
|
99
|
+
- !ruby/object:Gem::Version
|
100
|
+
version: '0'
|
101
|
+
requirements: []
|
102
|
+
rubyforge_project: morning-pages-journal
|
103
|
+
rubygems_version: 1.8.18
|
104
|
+
signing_key:
|
105
|
+
specification_version: 3
|
106
|
+
summary: Command line tool to manage morning pages
|
107
|
+
test_files:
|
108
|
+
- spec/morning-pages-journal/page_spec.rb
|
109
|
+
- spec/spec_helper.rb
|