woli 0.0.1.pre1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ /.bundle
2
+ /.config
3
+ /.yardoc
4
+ /Gemfile.lock
5
+ /doc
6
+ /pkg
7
+ /vendor/ruby
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in woli.gemspec
4
+ gemspec
@@ -0,0 +1,5 @@
1
+ guard 'minitest' do
2
+ watch(%r|^spec/(.*)_spec\.rb|)
3
+ watch(%r|^lib/(.*)\.rb|) { |m| "spec/#{m[1]}_spec.rb" }
4
+ watch(%r|^spec/spec_helper\.rb|) { "spec" }
5
+ end
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Jiří Stránský
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,26 @@
1
+ # Woli (as in WOrth LIving)
2
+
3
+ Geek's diary keeper, currently in pre-alpha state :)
4
+
5
+ ## Why would a grown person keep a diary?
6
+
7
+ * The ability to recall why a particular time of our life was worth living is crucial for your
8
+ long term happiness. Can you recall what you did during this week four years ago? If you can't,
9
+ it doesn't mean the week was not worth living, but it does mean that you can't derive a feeling
10
+ of happiness and satisfaction from knowing *why* it was worth living. Keeping a diary helps you
11
+ recall. You won't lose memories that are worth keeping.
12
+
13
+ * A diary helps you reflect on how you spent your time. In a long run, keeping a diary increases
14
+ your ability to recognize what's really important for you, what makes you happy. You will be
15
+ able to shape your days to contain more of those happy moments and important stuff. You will
16
+ be able to point your life in a direction that will bring you satisfaction and happiness.
17
+
18
+ The project was ignited by Radovan Bahbouh's inspiring TEDx talk "The Best Investment"
19
+ ([youtube video](http://www.youtube.com/watch?v=LNvExTsM2Xg), in Czech).
20
+
21
+ ## Tips
22
+
23
+ * At the end of the day, try to recall what important things happened. Recall why this day was
24
+ worth living. Write it down.
25
+
26
+ * Do not write just what happened, write also how you felt about it.
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
3
+ require 'rake/testtask'
4
+
5
+ task :default => [:test]
6
+
7
+ Rake::TestTask.new do |t|
8
+ t.pattern = "spec/**/*_spec.rb"
9
+ end
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+ require "rubygems" # ruby1.9 doesn't "require" it though
3
+
4
+ require 'woli/cli'
5
+
6
+ Woli::Cli.start
@@ -0,0 +1,36 @@
1
+ if ENV['DEBUG']
2
+ require 'pry'
3
+ end
4
+ require "woli/config"
5
+ require "woli/diary"
6
+ require "woli/diary_entry"
7
+ require "woli/version"
8
+ require "woli/repositories/files"
9
+
10
+ module Woli
11
+ def self.config
12
+ @config ||= Woli::Config.load_user_config
13
+ end
14
+
15
+ def self.diary
16
+ @diary ||= Woli::Diary.new(self.repository)
17
+ end
18
+
19
+ def self.editor
20
+ config['editor'] || ENV['EDITOR'] || 'vim'
21
+ end
22
+
23
+ def self.repository
24
+ @repository ||= instantiate_repository
25
+ end
26
+
27
+ class << self
28
+ private
29
+ def instantiate_repository
30
+ repository_class = config['repository_class'].split('::').reduce(Kernel) do |result_const, nested_const|
31
+ result_const = result_const.const_get(nested_const.to_sym)
32
+ end
33
+ repository_class.new(config['repository_config'])
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,13 @@
1
+ require 'woli'
2
+ require 'woli/date_parser'
3
+ require 'thor'
4
+
5
+ module Woli
6
+ class Cli < Thor
7
+ end
8
+ end
9
+
10
+ require 'woli/cli/edit'
11
+ require 'woli/cli/list'
12
+ require 'woli/cli/notify'
13
+ require 'woli/cli/status'
@@ -0,0 +1,41 @@
1
+ module Woli
2
+ class Cli
3
+ desc 'edit DAY', 'Edit a diary entry for a given day.'
4
+ long_desc <<-END
5
+ Edit a diary entry for a given day.
6
+
7
+ #{DateParser.parse_date_long_desc}
8
+ END
9
+ def edit(fuzzy_date = 'today')
10
+ date = DateParser.parse_date(fuzzy_date)
11
+ entry = Woli.repository.load_entry(date) || DiaryEntry.new(date, '', Woli.repository)
12
+
13
+ temp_file_name = generate_temp_file_name(entry)
14
+ save_text_to_temp_file(entry, temp_file_name)
15
+ edit_file_in_editor(temp_file_name)
16
+ load_text_from_temp_file(entry, temp_file_name)
17
+
18
+ entry.persist
19
+ end
20
+
21
+ private
22
+
23
+ def save_text_to_temp_file(entry, temp_file_name)
24
+ File.write(temp_file_name, entry.text)
25
+ end
26
+
27
+ def load_text_from_temp_file(entry, temp_file_name)
28
+ entry.text = File.read(temp_file_name)
29
+ File.delete(temp_file_name)
30
+ end
31
+
32
+ def generate_temp_file_name(entry)
33
+ "/tmp/woli_edit_entry_#{entry.date.strftime('%Y_%m_%d')}.#{Woli.config['edit_entry_extension']}"
34
+ end
35
+
36
+ def edit_file_in_editor(file_name)
37
+ tty = `tty`.strip
38
+ `#{Woli.editor} < #{tty} > #{tty} #{file_name}`
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,10 @@
1
+ module Woli
2
+ class Cli
3
+ desc 'list', 'List dates for which there are entries in the diary.'
4
+ def list
5
+ Woli.diary.all_entries_dates.each do |date|
6
+ puts date.strftime('%d-%m-%Y')
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,12 @@
1
+ module Woli
2
+ class Cli
3
+ desc 'notify', 'Get notified when you forget to write entries.'
4
+ def notify
5
+ notify_config = Woli.config['notification']['missing_entries']
6
+
7
+ if Woli.diary.missing_entries_count >= notify_config['days']
8
+ `#{notify_config['command']}`
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,17 @@
1
+ module Woli
2
+ class Cli
3
+ desc 'status', 'Print basic information about the diary.'
4
+ def status
5
+ entries_dates = Woli.diary.all_entries_dates
6
+ date_format = '%d-%m-%Y'
7
+ coverage = entries_dates.count / Float(entries_dates.last - entries_dates.first + 1)
8
+
9
+ puts "Woli Diary Status"
10
+ puts "================="
11
+ puts "First entry: #{entries_dates.first.strftime(date_format)}"
12
+ puts "Last entry: #{entries_dates.last.strftime(date_format)}"
13
+ puts "Coverage: %2d %" % (coverage * 100).round
14
+ puts "Missing entries since the last one: #{Woli.diary.missing_entries_count}"
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,19 @@
1
+ require 'yaml'
2
+
3
+ module Woli
4
+ class Config
5
+ CONFIG_FILE_NAME = "#{ENV['HOME']}/.woli/config.yml"
6
+ DEFAULT_CONFIG_FILE_NAME = File.join(File.dirname(__FILE__),
7
+ '../../templates/default_config.yml')
8
+
9
+ def self.load_user_config
10
+ create_default_config_file(CONFIG_FILE_NAME) unless File.exists?(CONFIG_FILE_NAME)
11
+ YAML.load_file(CONFIG_FILE_NAME)
12
+ end
13
+
14
+ def self.create_default_config_file(file_name)
15
+ FileUtils.mkdir_p(File.dirname(file_name))
16
+ FileUtils.cp(DEFAULT_CONFIG_FILE_NAME, file_name)
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,44 @@
1
+ module Woli
2
+ module DateParser
3
+ def self.parse_date_long_desc
4
+ <<-END
5
+ Specifying DAY:
6
+
7
+ 1) Implicitly: If no date is given, 'today' is assumed.
8
+
9
+ 2) Via a keyword: woli edit DAYNAME
10
+ (Where DAYNAME can be:
11
+ 'today' or 't';
12
+ 'yesterday' or 'y')
13
+
14
+ 3) Via a date: woli edit DD[-MM[-YYYY]]
15
+ (Use hyphens, dots or slashes to separate day/month/year.
16
+ If year or month is not given, current year / current month is assumed.)
17
+
18
+ 4) Via days ago: woli edit ^DAYS
19
+ (Where DAYS is a number of days ago. ^1 is yesterday, ^7 is a week ago etc.)
20
+ END
21
+ end
22
+
23
+ def self.parse_date(fuzzy_date)
24
+ case fuzzy_date
25
+ when 'today', 't', nil
26
+ Date.today
27
+ when 'yesterday', 'y'
28
+ Date.today - 1
29
+ when /\A\^(?<days_ago>\d+)/
30
+ Date.today - Integer($~[:days_ago])
31
+ when /\A(?<day>\d+)([-\.\/](?<month>\d+)([-\.\/](?<year>\d+))?)?\Z/
32
+ today = Date.today
33
+ year = $~[:year] ? Integer($~[:year]) : today.year
34
+ month = $~[:month] ? Integer($~[:month]) : today.month
35
+ day = $~[:day] ? Integer($~[:day]) : today.day
36
+ Date.new(year, month, day)
37
+ else
38
+ self.class.task_help(shell, 'edit')
39
+ puts
40
+ raise MalformattedArgumentError, "'#{fuzzy_date}' is not a valid way to specify a date."
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,30 @@
1
+ module Woli
2
+ class Diary
3
+ attr_reader :repository
4
+
5
+ def initialize(repository)
6
+ @repository = repository
7
+ end
8
+
9
+ def all_entries_dates
10
+ @repository.all_entries_dates
11
+ end
12
+
13
+ def entry(date)
14
+ @repository.load_entry(date)
15
+ end
16
+
17
+ def load_or_create_entry(date)
18
+ entry = @repository.load_entry(date)
19
+ return entry if entry
20
+
21
+ DiaryEntry.new(date, '', @repository)
22
+ end
23
+
24
+ def missing_entries_count
25
+ last_entry_date = @repository.all_entries_dates.last
26
+ return 0 unless last_entry_date
27
+ Date.today - last_entry_date
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,21 @@
1
+ module Woli
2
+ class DiaryEntry
3
+ attr_reader :repository, :date
4
+ attr_accessor :text
5
+
6
+ def initialize(date, text, repository)
7
+ @date = date
8
+ @text = text
9
+ @repository = repository
10
+ end
11
+
12
+ def persist
13
+ if text.strip.length > 0
14
+ repository.save_entry(self)
15
+ else
16
+ puts "Empty entry -- removing."
17
+ repository.delete_entry(self)
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,61 @@
1
+ module Woli
2
+ module Repositories
3
+ class Files
4
+ attr_reader :config
5
+
6
+ def initialize(config)
7
+ @config = config
8
+ end
9
+
10
+ def all_entries_dates
11
+ all_entries_files.map { |filename|
12
+ match_data = filename.match /(?<year>[0-9]{4})-(?<month>[0-9]{2})-(?<day>[0-9]{2}).#{Regexp.escape(config['entry_extension'])}\Z/
13
+ Date.new(match_data[:year].to_i, match_data[:month].to_i, match_data[:day].to_i)
14
+ }.sort
15
+ end
16
+
17
+ def load_entry(date)
18
+ file_name = path_for_entry_date(date)
19
+ return nil unless File.exists? file_name
20
+
21
+ text = File.read(path_for_entry_date(date))
22
+ DiaryEntry.new(date, text, self)
23
+ end
24
+
25
+ def save_entry(entry)
26
+ File.write(path_for_entry_date(entry.date), entry.text)
27
+ end
28
+
29
+ def delete_entry(entry)
30
+ file_name = path_for_entry_date(entry.date)
31
+ return unless File.exists? file_name
32
+
33
+ File.delete(file_name)
34
+ end
35
+
36
+ private
37
+
38
+ def diary_path
39
+ File.expand_path(config['path'])
40
+ end
41
+
42
+ def path_for_entry_date(date)
43
+ File.join(
44
+ diary_path,
45
+ date.strftime('%Y'),
46
+ date.strftime('%m'),
47
+ date.strftime("%Y-%m-%d.#{config['entry_extension']}")
48
+ )
49
+ end
50
+
51
+ def all_entries_files
52
+ entry_like_filenames = Dir.glob(File.join(diary_path, '**', '*.' + config['entry_extension']))
53
+
54
+ # Globbing is not enough -> filter the results further with regexps.
55
+ entry_like_filenames.select do |filename|
56
+ filename =~ %r{#{Regexp.escape(diary_path)}/[0-9]{4}/[0-9]{2}/[0-9]{4}-[0-9]{2}-[0-9]{2}.#{Regexp.escape(config['entry_extension'])}\Z}
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,3 @@
1
+ module Woli
2
+ VERSION = "0.0.1.pre1"
3
+ end
@@ -0,0 +1,6 @@
1
+ require 'minitest/spec'
2
+ require 'minitest/autorun'
3
+ begin; require 'turn'; rescue LoadError; end
4
+ require 'mocha'
5
+ require 'timecop'
6
+
@@ -0,0 +1,68 @@
1
+ require_relative '../spec_helper'
2
+ require 'woli/date_parser'
3
+
4
+ describe Woli::DateParser do
5
+ before do
6
+ @parser = Woli::DateParser
7
+ @today = Date.new(2012, 7, 15)
8
+ Timecop.freeze(@today)
9
+ end
10
+
11
+ after do
12
+ Timecop.return
13
+ end
14
+
15
+ it "parses nil as today" do
16
+ @parser.parse_date(nil).must_equal @today
17
+ end
18
+
19
+ it "parses 't' and 'today' as today" do
20
+ @parser.parse_date('t').must_equal @today
21
+ @parser.parse_date('today').must_equal @today
22
+ end
23
+
24
+ it "parses 'y' and 'yesterday' as yesterday" do
25
+ @parser.parse_date('y').must_equal (@today - 1)
26
+ @parser.parse_date('yesterday').must_equal (@today - 1)
27
+ end
28
+
29
+ it "parses '^2' as 2 days ago" do
30
+ @parser.parse_date('^2').must_equal (@today - 2)
31
+ end
32
+
33
+ it "parses '^50' as 50 days ago" do
34
+ @parser.parse_date('^50').must_equal (@today - 50)
35
+ end
36
+
37
+ it "parses '20' as 20th day of current month" do
38
+ parsed = @parser.parse_date('20')
39
+ parsed.year.must_equal @today.year
40
+ parsed.month.must_equal @today.month
41
+ parsed.day.must_equal 20
42
+ end
43
+
44
+ it "parses '20.2' as 20th February of current year" do
45
+ parsed = @parser.parse_date('20.2')
46
+ parsed.year.must_equal @today.year
47
+ parsed.month.must_equal 2
48
+ parsed.day.must_equal 20
49
+ end
50
+
51
+ it "parses '20/2/2011' as 20th February 2011" do
52
+ parsed = @parser.parse_date('20/2/2011')
53
+ parsed.year.must_equal 2011
54
+ parsed.month.must_equal 2
55
+ parsed.day.must_equal 20
56
+ end
57
+
58
+ it "parses '20.4', '20-4', '20/4', '20-4-2012' as the same dates (current year is 2012)" do
59
+ date1 = @parser.parse_date('20.4')
60
+ date2 = @parser.parse_date('20-4')
61
+ date3 = @parser.parse_date('20/4')
62
+ date4 = @parser.parse_date('20-4-2012')
63
+
64
+ date1.must_equal date2
65
+ date1.must_equal date3
66
+ date1.must_equal date4
67
+ end
68
+ end
@@ -0,0 +1,47 @@
1
+ require_relative '../spec_helper'
2
+ require 'woli/diary_entry'
3
+
4
+ describe Woli::DiaryEntry do
5
+ before do
6
+ @repository = mock 'repository'
7
+ end
8
+
9
+ describe "empty entry" do
10
+ before do
11
+ @entry = Woli::DiaryEntry.new(Date.new(2012, 7, 14), '', @repository)
12
+ end
13
+
14
+ it "removes itself from the repository when persisting its state" do
15
+ @repository.expects(:delete_entry).with(@entry)
16
+ @entry.persist
17
+ end
18
+ end
19
+
20
+ describe "pseudoempty entry (whitespace only)" do
21
+ before do
22
+ @entry = Woli::DiaryEntry.new(Date.new(2012, 7, 14), "\n\n \n", @repository)
23
+ end
24
+
25
+ it "removes itself from the repository when persisting its state" do
26
+ @repository.expects(:delete_entry).with(@entry)
27
+ @entry.persist
28
+ end
29
+ end
30
+
31
+ describe "filled in entry" do
32
+ before do
33
+ text = <<-END
34
+ * Today I had the best ice cream.
35
+
36
+ * I slipped on a banana and didn't break anything. Yay!
37
+ END
38
+ @entry = Woli::DiaryEntry.new(Date.new(2012, 7, 14), text, @repository)
39
+ end
40
+
41
+ it "saves itself into the repository when persisting its state" do
42
+ @repository.expects(:save_entry).with(@entry)
43
+ @entry.persist
44
+ end
45
+ end
46
+ end
47
+
@@ -0,0 +1,69 @@
1
+ require_relative '../spec_helper'
2
+ require 'woli/diary'
3
+
4
+ describe Woli::Diary do
5
+ before do
6
+ @existing_entry = mock 'existing diary entry'
7
+ @existing_entry_date = Date.new(2012, 7, 1)
8
+ @nonexistent_entry_date = Date.new(2012, 7, 16)
9
+
10
+ @repository = mock 'repository'
11
+ @repository.stubs(:load_entry).with(@existing_entry_date).returns(@existing_entry)
12
+ @repository.stubs(:load_entry).with(@nonexistent_entry_date).returns(nil)
13
+ @repository.stubs(:all_entries_dates).returns([@existing_entry_date])
14
+
15
+ @diary = Woli::Diary.new(@repository)
16
+ end
17
+
18
+ describe "#entry" do
19
+ it "loads an existing entry" do
20
+ @diary.entry(@existing_entry_date).must_equal @existing_entry
21
+ end
22
+
23
+ it "returns nil for a non-existent entry" do
24
+ @diary.entry(@nonexistent_entry_date).must_equal nil
25
+ end
26
+ end
27
+
28
+ describe "#load_or_create_entry" do
29
+ before do
30
+ @new_entry = :fake_new_entry
31
+ class Woli::DiaryEntry ; end
32
+ Woli::DiaryEntry.stubs(:new).with(@nonexistent_entry_date, '', @repository).returns(@new_entry)
33
+ end
34
+
35
+ it "loads an existing entry" do
36
+ @diary.load_or_create_entry(@existing_entry_date).must_equal @existing_entry
37
+ end
38
+
39
+ it "creates a new entry for a non-existent entry" do
40
+ @diary.load_or_create_entry(@nonexistent_entry_date).must_equal @new_entry
41
+ end
42
+ end
43
+
44
+ describe "#all_entries_dates" do
45
+ it "delegates the call to the repository" do
46
+ @diary.all_entries_dates.must_equal @repository.all_entries_dates
47
+ end
48
+ end
49
+
50
+ describe "#missing_entries_count" do
51
+ it "returns 0 when the last entry is for today" do
52
+ Timecop.freeze(@repository.all_entries_dates.last) do
53
+ @diary.missing_entries_count.must_equal 0
54
+ end
55
+ end
56
+
57
+ it "returns 1 when the last entry is for yesterday" do
58
+ Timecop.freeze(@repository.all_entries_dates.last + 1) do
59
+ @diary.missing_entries_count.must_equal 1
60
+ end
61
+ end
62
+
63
+ it "returns 7 when the last entry is for a day week ago" do
64
+ Timecop.freeze(@repository.all_entries_dates.last + 7) do
65
+ @diary.missing_entries_count.must_equal 7
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,98 @@
1
+ require_relative '../../spec_helper'
2
+ require 'woli/repositories/files'
3
+
4
+ describe Woli::Repositories::Files do
5
+ before do
6
+ @config = {
7
+ 'path' => '/tmp/fake_diary_path',
8
+ 'entry_extension' => 'md'
9
+ }
10
+
11
+ @repository = Woli::Repositories::Files.new(@config)
12
+
13
+ @entry = stub(
14
+ :date => Date.new(2012, 7, 6),
15
+ :text => 'entry text',
16
+ :repository => @repository
17
+ )
18
+ @entry_path = "#{@config['path']}/2012/07/2012-07-06.#{@config['entry_extension']}"
19
+ end
20
+
21
+ describe "#all_entries_dates" do
22
+ before do
23
+ Dir.stubs(:glob)
24
+ .with("#{@config['path']}/**/*.#{@config['entry_extension']}")
25
+ .returns([
26
+ "#{@config['path']}/2012/07/2012-07-06.#{@config['entry_extension']}",
27
+ "#{@config['path']}/2012/07/2012-07-04.#{@config['entry_extension']}",
28
+ "#{@config['path']}/2012/07/2012-07-05.#{@config['entry_extension']}",
29
+ "#{@config['path']}/2012/07/maliciously_named_file.#{@config['entry_extension']}",
30
+ "#{@config['path']}/2012/07/2012-07-03-this-aint-right.#{@config['entry_extension']}"
31
+ ])
32
+ end
33
+
34
+ it "returns correct and sorted dates for correctly named entry files, ignores others" do
35
+ @repository.all_entries_dates.must_equal [
36
+ Date.new(2012, 7, 4),
37
+ Date.new(2012, 7, 5),
38
+ Date.new(2012, 7, 6)
39
+ ]
40
+ end
41
+ end
42
+
43
+ describe "#load_entry" do
44
+ it "loads an entry from a file" do
45
+ new_entry = :fake_new_entry
46
+
47
+ File.expects(:exists?)
48
+ .with(@entry_path)
49
+ .returns(true)
50
+
51
+ File.expects(:read)
52
+ .with(@entry_path)
53
+ .returns('entry text')
54
+
55
+ class Woli::DiaryEntry; end
56
+ Woli::DiaryEntry.expects(:new).with(@entry.date, 'entry text', @repository).returns(new_entry)
57
+
58
+ @repository.load_entry(@entry.date).must_equal(new_entry)
59
+ end
60
+
61
+ it "returns nil if file for that date doesn't exist" do
62
+ File.expects(:exists?)
63
+ .with(@entry_path)
64
+ .returns(false)
65
+
66
+ @repository.load_entry(@entry.date).must_be_nil
67
+ end
68
+ end
69
+
70
+ describe "#save_entry" do
71
+ it "writes the text into a file" do
72
+ File.expects(:write).with(@entry_path, @entry.text).returns(@entry.text.length)
73
+
74
+ @repository.save_entry(@entry)
75
+ end
76
+ end
77
+
78
+ describe "#delete_entry" do
79
+ it "does nothing if the file does not exist" do
80
+ File.expects(:exists?)
81
+ .with(@entry_path)
82
+ .returns(false)
83
+
84
+ @repository.delete_entry(@entry).must_be_nil
85
+ end
86
+
87
+ it "deletes the file with entry contents" do
88
+ File.expects(:exists?)
89
+ .with(@entry_path)
90
+ .returns(true)
91
+ File.expects(:delete)
92
+ .with(@entry_path)
93
+ .returns(1)
94
+
95
+ @repository.delete_entry(@entry)
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,12 @@
1
+ repository_class: 'Woli::Repositories::Files'
2
+ repository_config:
3
+ path: ~/.woli/diary
4
+ entry_extension: md
5
+
6
+ editor:
7
+ edit_entry_extension: md
8
+
9
+ notification:
10
+ missing_entries:
11
+ days: 1
12
+ command: "notify-send 'Woli diary is hungry for entries.'"
@@ -0,0 +1,44 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/woli/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.authors = ["Jiří Stránský"]
6
+ gem.email = ["jistr@jistr.com"]
7
+ gem.description = <<-END
8
+ Woli (as in WOrth LIving) helps you record your memories. Write
9
+ a short note about every day you live and make sure your days are worth
10
+ living. Later, review your notes to bring back the memories.
11
+ Change your life if you are not happy with what's in your diary.
12
+ END
13
+ gem.summary = "Woli, the diary keeper."
14
+ gem.homepage = "http://github.com/jistr/woli"
15
+
16
+ gem.files = `git ls-files`.split($\)
17
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
18
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
19
+ gem.name = "woli"
20
+ gem.require_paths = ["lib"]
21
+ gem.version = Woli::VERSION
22
+
23
+ gem.add_dependency 'thor', '~> 0.15.2'
24
+
25
+ # == DEVELOPMENT DEPENDENCIES ==
26
+ # Smart irb
27
+ gem.add_development_dependency 'pry'
28
+
29
+ # Specs
30
+ gem.add_development_dependency 'minitest'
31
+ gem.add_development_dependency 'mocha'
32
+ gem.add_development_dependency 'timecop'
33
+
34
+ # Running tests during development
35
+ gem.add_development_dependency 'guard'
36
+ gem.add_development_dependency 'guard-minitest'
37
+ # Linux Guard watching
38
+ gem.add_development_dependency 'rb-inotify'
39
+ # Linux Guard notifications
40
+ gem.add_development_dependency 'libnotify'
41
+
42
+ # Pretty printed test output
43
+ gem.add_development_dependency 'turn'
44
+ end
metadata ADDED
@@ -0,0 +1,193 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: woli
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1.pre1
5
+ prerelease: 6
6
+ platform: ruby
7
+ authors:
8
+ - Jiří Stránský
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-07-16 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: thor
16
+ requirement: &16096140 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: 0.15.2
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *16096140
25
+ - !ruby/object:Gem::Dependency
26
+ name: pry
27
+ requirement: &16095460 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: *16095460
36
+ - !ruby/object:Gem::Dependency
37
+ name: minitest
38
+ requirement: &16094260 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ! '>='
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
44
+ type: :development
45
+ prerelease: false
46
+ version_requirements: *16094260
47
+ - !ruby/object:Gem::Dependency
48
+ name: mocha
49
+ requirement: &16093600 !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ type: :development
56
+ prerelease: false
57
+ version_requirements: *16093600
58
+ - !ruby/object:Gem::Dependency
59
+ name: timecop
60
+ requirement: &16092680 !ruby/object:Gem::Requirement
61
+ none: false
62
+ requirements:
63
+ - - ! '>='
64
+ - !ruby/object:Gem::Version
65
+ version: '0'
66
+ type: :development
67
+ prerelease: false
68
+ version_requirements: *16092680
69
+ - !ruby/object:Gem::Dependency
70
+ name: guard
71
+ requirement: &16091900 !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - ! '>='
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ type: :development
78
+ prerelease: false
79
+ version_requirements: *16091900
80
+ - !ruby/object:Gem::Dependency
81
+ name: guard-minitest
82
+ requirement: &16091300 !ruby/object:Gem::Requirement
83
+ none: false
84
+ requirements:
85
+ - - ! '>='
86
+ - !ruby/object:Gem::Version
87
+ version: '0'
88
+ type: :development
89
+ prerelease: false
90
+ version_requirements: *16091300
91
+ - !ruby/object:Gem::Dependency
92
+ name: rb-inotify
93
+ requirement: &16106680 !ruby/object:Gem::Requirement
94
+ none: false
95
+ requirements:
96
+ - - ! '>='
97
+ - !ruby/object:Gem::Version
98
+ version: '0'
99
+ type: :development
100
+ prerelease: false
101
+ version_requirements: *16106680
102
+ - !ruby/object:Gem::Dependency
103
+ name: libnotify
104
+ requirement: &16106120 !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ! '>='
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ type: :development
111
+ prerelease: false
112
+ version_requirements: *16106120
113
+ - !ruby/object:Gem::Dependency
114
+ name: turn
115
+ requirement: &16105220 !ruby/object:Gem::Requirement
116
+ none: false
117
+ requirements:
118
+ - - ! '>='
119
+ - !ruby/object:Gem::Version
120
+ version: '0'
121
+ type: :development
122
+ prerelease: false
123
+ version_requirements: *16105220
124
+ description: ! " Woli (as in WOrth LIving) helps you record your memories. Write\n
125
+ \ a short note about every day you live and make sure your days are worth\n living.
126
+ Later, review your notes to bring back the memories.\n Change your life if you
127
+ are not happy with what's in your diary.\n"
128
+ email:
129
+ - jistr@jistr.com
130
+ executables:
131
+ - woli
132
+ extensions: []
133
+ extra_rdoc_files: []
134
+ files:
135
+ - .gitignore
136
+ - Gemfile
137
+ - Guardfile
138
+ - LICENSE
139
+ - README.md
140
+ - Rakefile
141
+ - bin/woli
142
+ - lib/woli.rb
143
+ - lib/woli/cli.rb
144
+ - lib/woli/cli/edit.rb
145
+ - lib/woli/cli/list.rb
146
+ - lib/woli/cli/notify.rb
147
+ - lib/woli/cli/status.rb
148
+ - lib/woli/config.rb
149
+ - lib/woli/date_parser.rb
150
+ - lib/woli/diary.rb
151
+ - lib/woli/diary_entry.rb
152
+ - lib/woli/repositories/files.rb
153
+ - lib/woli/version.rb
154
+ - spec/spec_helper.rb
155
+ - spec/woli/date_parser_spec.rb
156
+ - spec/woli/diary_entry_spec.rb
157
+ - spec/woli/diary_spec.rb
158
+ - spec/woli/repositories/files_spec.rb
159
+ - templates/default_config.yml
160
+ - woli.gemspec
161
+ homepage: http://github.com/jistr/woli
162
+ licenses: []
163
+ post_install_message:
164
+ rdoc_options: []
165
+ require_paths:
166
+ - lib
167
+ required_ruby_version: !ruby/object:Gem::Requirement
168
+ none: false
169
+ requirements:
170
+ - - ! '>='
171
+ - !ruby/object:Gem::Version
172
+ version: '0'
173
+ segments:
174
+ - 0
175
+ hash: -2448595754877266534
176
+ required_rubygems_version: !ruby/object:Gem::Requirement
177
+ none: false
178
+ requirements:
179
+ - - ! '>'
180
+ - !ruby/object:Gem::Version
181
+ version: 1.3.1
182
+ requirements: []
183
+ rubyforge_project:
184
+ rubygems_version: 1.8.11
185
+ signing_key:
186
+ specification_version: 3
187
+ summary: Woli, the diary keeper.
188
+ test_files:
189
+ - spec/spec_helper.rb
190
+ - spec/woli/date_parser_spec.rb
191
+ - spec/woli/diary_entry_spec.rb
192
+ - spec/woli/diary_spec.rb
193
+ - spec/woli/repositories/files_spec.rb