rb-dayone 0.2.0 → 0.3.3

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile CHANGED
@@ -1,4 +1,5 @@
1
1
  source :rubygems
2
2
 
3
3
  gem 'builder', '~> 2.0'
4
- gem 'commander', '~> 4.1.2'
4
+ gem 'commander', '~> 4.1.2'
5
+ gem 'libxml-ruby', '~> 2.3.3'
data/History.rdoc CHANGED
@@ -1,3 +1,26 @@
1
+ == 0.3.3 / 2012-08-17
2
+
3
+ * [FIXED] LibXML will now accept UTF-8 characters in journal entries.
4
+ * Added the command "repair" to the dayone binary, which will at least repair *my* damage.
5
+ * Added the command "verify" to the dayone binary, which I at least find helpful.
6
+ * Added a post-install note telling people upgrading from <= 0.2.0 to repair.
7
+
8
+ == 0.3.2 / 2012-08-16
9
+
10
+ * Switched from REXML to LibXML-ruby for XML parsing. Now accepts ampersands in entries, as well as UTF-8. Rejoice!
11
+
12
+ == 0.3.1 / 2012-08-16
13
+
14
+ * [FIXED] Minor bugfixes
15
+ * [FIXED] REXML will no longer kill the whole program if it can't parse a journal file.
16
+
17
+ == 0.3.0 / 2012-08-16
18
+
19
+ * [FIXED] Fixed several bugs in Builder xml output, including:
20
+ * Output of trailing <target />
21
+ * Output of malformed DOCTYPE
22
+ * You can now import existing DayOne entries and search them
23
+
1
24
  == 0.2.0 / 2012-08-14
2
25
 
3
26
  * Now auto-detects DayOne journal location from your plist file
data/Manifest CHANGED
@@ -3,16 +3,26 @@ Gemfile
3
3
  History.rdoc
4
4
  lib/rb-dayone.rb
5
5
  lib/rb-dayone/entry.rb
6
+ lib/rb-dayone/entry_importer.rb
6
7
  lib/rb-dayone/plist_reader.rb
8
+ lib/rb-dayone/search.rb
7
9
  Manifest
10
+ Rakefile
8
11
  rb-dayone.gemspec
9
12
  README.md
13
+ spec/data/entries/748AD5D252F44149920485B0CEA478E3.doentry
14
+ spec/data/entries/F13723CDFD454481B24312DCD627BFD7.doentry
15
+ spec/data/foo.doentry
16
+ spec/data/locations/location-auto/location
17
+ spec/data/locations/location-specified/location
18
+ spec/data/locations/location-unspecified
19
+ spec/data/sample.doentry
20
+ spec/data/sample.plist
21
+ spec/data/utf.doentry
10
22
  spec/dayone_spec.rb
23
+ spec/entry_importer_spec.rb
11
24
  spec/entry_spec.rb
12
- spec/locations/location-auto/location
13
- spec/locations/location-specified/location
14
- spec/locations/location-unspecified
15
- spec/spec_helper.rb
16
25
  spec/plist_reader_spec.rb
17
- spec/sample.plist
26
+ spec/search_spec.rb
27
+ spec/spec_helper.rb
18
28
  version.txt
data/README.md CHANGED
@@ -29,21 +29,32 @@ For more information on what you can do from the command line:
29
29
 
30
30
  dayone --help
31
31
 
32
+ ### Validating and repairing doentry files ###
33
+
34
+ As of version 0.2.0 of this gem, `rb-dayone` is finally outputting *nice* XML. Before then, it wasn't. You can check if any of your DayOne entries need repairing by running:
35
+
36
+ dayone validate
37
+
38
+ If they do, you might be able to fix them using:
39
+
40
+ dayone repair
41
+
42
+ If not, let me know, and I'll see what I can do to fix stuff.
43
+
32
44
  ## Install
33
45
 
34
46
  gem install rb-dayone
35
47
 
36
48
  ## Author
37
49
 
38
- Original author: Jan-Yves Ruzicka (@akchizar). Get in touch [via email](mailto:janyves.ruzicka@gmail.com).
50
+ Original author: [Jan-Yves Ruzicka](http://www.1klb.com) ([@akchizar](http://www.twitter.com/akchizar)). Get in touch [via email](mailto:janyves.ruzicka@gmail.com).
39
51
 
40
52
  ## To do
41
53
 
42
54
  * Image support
43
55
  * Location support?
44
56
 
45
- License
46
- -------
57
+ ## License
47
58
 
48
59
  Copyright (c) 2012 Jan-Yves Ruzicka
49
60
 
data/Rakefile ADDED
@@ -0,0 +1,34 @@
1
+ gem_title = 'rb-dayone'
2
+
3
+ def pkg
4
+ p = Dir['pkg/*.gem'].sort[-1]
5
+ if p.nil?
6
+ $stderr.puts "ERROR: Can't find pkg file."
7
+ else
8
+ p
9
+ end
10
+ end
11
+
12
+ task :build do
13
+ specfile = "#{gem_title}.gemspec"
14
+ sh "gem build '#{specfile}'"
15
+
16
+ gem_file = Dir["#{gem_title}-*.gem"]
17
+ gem_file.each do |f|
18
+ sh "mv '#{f}' pkg"
19
+ end
20
+ end
21
+
22
+ task :install => [:build] do
23
+ sh "gem install #{pkg}"
24
+ end
25
+
26
+ task :push => [:build] do
27
+ sh "gem push #{pkg}"
28
+ end
29
+
30
+ task :spec do
31
+ sh "rspec"
32
+ end
33
+
34
+ task :default => :spec
data/bin/dayone CHANGED
@@ -61,4 +61,75 @@ If you don't specify the --text tag, it will read text from STDIN and use this a
61
61
  entry = DayOne::Entry.new entry_text, starred:starred
62
62
  entry.create!
63
63
  end
64
+ end
65
+
66
+ command :repair do |c|
67
+ c.syntax = "repair"
68
+ c.description = "Will repair any damage caused by previous versions of rb-dayone."
69
+ c.summary = "This command will trawl your DayOne journal archive looking for any malformed DayOne entries created by previous versions of rb-dayone, and will fix them. Currently it fixed malformed doctype declarations and trailing target tags."
70
+
71
+ c.action do |args, opts|
72
+ require 'rb-dayone'
73
+
74
+ repairs = {
75
+ 'trailing target' => [
76
+ /<target\/>\Z/,
77
+ ''
78
+ ],
79
+ 'malformed doctype' => [
80
+ %r|<!DOCTYPE "plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"">|,
81
+ %|<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">|
82
+ ]
83
+ }
84
+
85
+ DayOne.entries.each do |f|
86
+ contents = File.read(f)
87
+ modified = []
88
+ repairs.each do |name, (replace_this, with_this)|
89
+ if replace_this === contents
90
+ modified << name
91
+ contents = contents.gsub(replace_this, with_this)
92
+ end
93
+ end
94
+
95
+ unless modified.empty?
96
+ File.open(f,'w'){ |io| io.puts contents }
97
+ puts "Repaired file #{f}:"
98
+ modified.each{ |s| puts " Fixed #{s}" }
99
+ end
100
+ end
101
+ puts "All files have been repaired!"
102
+ end
103
+ end
104
+
105
+ command :validate do |c|
106
+ c.syntax = "validate"
107
+ c.description = "Checks through your DayOne database to see if any of your journal entries break XML validation."
108
+
109
+ c.action do
110
+ require 'libxml'
111
+ require 'rb-dayone'
112
+
113
+ LibXML::XML::Error.set_handler(&LibXML::XML::Error::QUIET_HANDLER)
114
+ failed_entries = []
115
+
116
+ all_entries = DayOne.entries
117
+ puts "Checking #{all_entries.size} entr#{all_entries.size == 1 ? 'y' : 'ies'}..."
118
+
119
+ all_entries.each do |f|
120
+ begin
121
+ contents = File.read(f)
122
+ LibXML::XML::Parser.string(contents).parse
123
+ rescue LibXML::XML::Error
124
+ failed_entries << f
125
+ end
126
+ end
127
+
128
+ if failed_entries.empty?
129
+ puts "No errors. Everything is OK!"
130
+ else
131
+ puts "#{failed_entries.size} error#{failed_entries.size == 1 ? '' : 's'} in validation:"
132
+ failed_entries.each{ |f| puts " #{f}" }
133
+ end
134
+ end
64
135
  end
data/lib/rb-dayone.rb CHANGED
@@ -42,6 +42,12 @@ module DayOne
42
42
  @auto_journal_location ||= File.expand_path(plist_reader['NSNavLastRootDirectory'])
43
43
  end
44
44
 
45
+ # All DayOne entries, as file names
46
+ # @return [Array] all DayOne entries
47
+ def entries
48
+ Dir[File.join(journal_location, 'entries','*.doentry')]
49
+ end
50
+
45
51
  private
46
52
 
47
53
  # The journal file location
@@ -1,3 +1,5 @@
1
+ require 'libxml'
2
+
1
3
  # A text-only journal entry for DayOne.
2
4
  class DayOne::Entry
3
5
 
@@ -10,8 +12,11 @@ class DayOne::Entry
10
12
  # Whether the entry has been starred
11
13
  attr_accessor :starred
12
14
 
15
+ # Whether the entry has been saved to file at all.
16
+ attr_accessor :saved
17
+
13
18
  # The PList doctype, used for XML export
14
- DOCTYPE = 'plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"'
19
+ DOCTYPE = [:DOCTYPE, :plist, :PUBLIC, "-//Apple//DTD PLIST 1.0//EN", "http://www.apple.com/DTDs/PropertyList-1.0.dtd"]
15
20
 
16
21
  # Initialise a journal entry, ready for inclusion into your journal
17
22
  # @param [String] entry_text the body text of the journal entry
@@ -22,6 +27,7 @@ class DayOne::Entry
22
27
  @creation_date = Time.now
23
28
  @starred = false
24
29
  @entry_text = entry_text
30
+ @saved = false
25
31
 
26
32
  hsh.each do |k,v|
27
33
  setter = "#{k}="
@@ -36,12 +42,17 @@ class DayOne::Entry
36
42
  @uuid ||= `uuidgen`.gsub('-','').strip
37
43
  end
38
44
 
45
+ # The same as calling Entry#saved
46
+ def saved?
47
+ saved
48
+ end
49
+
39
50
  # Convert an entry to XML.
40
51
  # @return [String] the entry as XML
41
52
  def to_xml
42
- builder = Builder::XmlMarkup.new
53
+ builder = Builder::XmlMarkup.new(indent:2)
43
54
  builder.instruct! # Basic xml tag
44
- builder.declare! :DOCTYPE, DOCTYPE # PList doctype
55
+ builder.declare! *DOCTYPE # PList doctype
45
56
  builder.plist(version:1.0) do
46
57
  builder.dict do
47
58
  builder.key 'Creation Date'
@@ -61,7 +72,7 @@ class DayOne::Entry
61
72
  builder.string uuid
62
73
  end
63
74
  end
64
- builder.target
75
+ builder.target!
65
76
  end
66
77
 
67
78
  # Create a .doentry file with this entry.
@@ -74,4 +85,16 @@ class DayOne::Entry
74
85
  File.open(file_location,'w'){ |io| io << xml }
75
86
  return true
76
87
  end
88
+
89
+ # Check to make sure that we output valid xml
90
+ def xml_valid?
91
+ LibXML::XML::Error.set_handler(&LibXML::XML::Error::QUIET_HANDLER)
92
+ begin
93
+ LibXML::XML::Parser.string(to_xml).parse
94
+ rescue LibXML::XML::Error
95
+ return false
96
+ else
97
+ return true
98
+ end
99
+ end
77
100
  end
@@ -0,0 +1,78 @@
1
+ require 'libxml'
2
+
3
+ # Imports DayOne entries from XML files or plain text
4
+ class DayOne::EntryImporter
5
+
6
+ # Raw data as provided in initialize
7
+ attr_accessor :data
8
+
9
+ # File (if supplied)
10
+ attr_accessor :file
11
+
12
+ # Create a new entry based on a string. To import from a file,
13
+ # use EntryImporter.from_file.
14
+ # @param [String] data The raw data for the importer to process
15
+ def initialize data
16
+ @data = data
17
+ end
18
+
19
+ # Create a new entry from a file
20
+ # @param [String] file The file to import
21
+ def self.from_file file
22
+ ei = new(File.read(file))
23
+ ei.file = file
24
+ ei
25
+ end
26
+
27
+ # Access entry data by key
28
+ # @param [String, Symbol] key The key to retrieve
29
+ # @return the value stored in the file, or nil
30
+ def [] key
31
+ processed_data[key]
32
+ end
33
+
34
+ # Generate and return the data contained within the doentry file, as a hash
35
+ # @return [Hash] the processed data
36
+ def processed_data
37
+ if !@processed_data
38
+ @processed_data = {}
39
+ LibXML::XML::Error.set_handler(&LibXML::XML::Error::QUIET_HANDLER)
40
+
41
+ begin
42
+ document = LibXML::XML::Parser.string(data).parse
43
+ key = nil
44
+
45
+ document.find('//plist/dict/*').each do |elem|
46
+ case elem.name
47
+ when 'key'
48
+ key = elem.content
49
+ when 'date'
50
+ if elem.content =~ /(\d+)-(\d+)-(\d+)T(\d+):(\d+):(\d+)Z/
51
+ @processed_data[key] = Time.new($1.to_i, $2.to_i, $3.to_i, $4.to_i, $5.to_i, $6.to_i)
52
+ end
53
+ when 'true'
54
+ @processed_data[key] = true
55
+ when 'false'
56
+ @processed_data[key] = false
57
+ else
58
+ @processed_data[key] = elem.content
59
+ end
60
+ end
61
+ rescue LibXML::XML::Error
62
+ $stderr.puts "Error parsing #{file ? "file #{file}" : "data"}. Skipping."
63
+ end
64
+ end
65
+ @processed_data
66
+ end
67
+
68
+ # Generate an entry from this importer
69
+ # @return a DayOne::Entry based on this importer
70
+ def to_entry
71
+ DayOne::Entry.new(
72
+ self['Entry Text'],
73
+ starred: self['Starred'],
74
+ creation_date: self['Creation Date'],
75
+ saved: true
76
+ )
77
+ end
78
+ end
@@ -1,12 +1,20 @@
1
1
  require 'json'
2
2
 
3
+ # The PListReader is a class that reads PLists.
4
+ # It is used to read the DayOne preferences PList.
3
5
  class DayOne::PlistReader
6
+
7
+ # The path of the PList to read.
4
8
  attr_accessor :path
5
9
 
10
+ # Initialize the PList Reader, given a path
11
+ # @param [String] path the path to the PList; defaults to the standard DayOne preference plist
6
12
  def initialize path=nil
7
13
  @path = path || File.join(ENV['HOME'], 'Library', 'Preferences', 'com.dayoneapp.dayone.plist')
8
14
  end
9
15
 
16
+ # Retrieve the body of the plist as an array, parsed through JSON
17
+ # @return [Hash] the body of the plist as a hash.
10
18
  def body
11
19
  if !@body
12
20
  json_string = `plutil -convert json -o - '#{path}'`
@@ -15,6 +23,7 @@ class DayOne::PlistReader
15
23
  @body
16
24
  end
17
25
 
26
+ # This allows us to access the body's method as well as the reader's.
18
27
  def method_missing sym, *args
19
28
  if self.body.respond_to? sym
20
29
  self.body.send(sym, *args)
@@ -0,0 +1,59 @@
1
+ # A search of the database.
2
+ # Create this object with Search.new. Give it some parameters to search for, then
3
+ # simple use Search#[] to access results.
4
+ class DayOne::Search
5
+
6
+ # The entry must include this text
7
+ attr_accessor :entry_text
8
+
9
+ # The entry must be starred
10
+ attr_accessor :starred
11
+
12
+ # Initialize the search. Currently you can only search by entry text and starred status,
13
+ # but both of these can be passed in via hash.
14
+ # @param [Hash] hash a hash of search criteria, including:
15
+ # * +entry_text+: Text that the entry must include
16
+ # * +starred+: whether the entry is starred or not
17
+ def initialize hash={}
18
+ @entry_text = ''
19
+ hash.each do |k,v|
20
+ setter = "#{k}="
21
+ self.send(setter, v) if self.respond_to?(setter)
22
+ end
23
+ end
24
+
25
+ # Fetch the results by searching. Uses a cached version of the DayOne database.
26
+ # @return [Array] all entries matching your results
27
+ def results
28
+ if !@results
29
+ @results = []
30
+ working_results = cache
31
+
32
+ working_results = working_results.select{ |e| e.entry_text.include? entry_text } unless entry_text == ''
33
+ working_results = working_results.select{ |e| e.starred == starred } unless starred.nil?
34
+
35
+ @results = working_results
36
+ end
37
+ @results
38
+ end
39
+
40
+ # Fetches a particular result
41
+ # @param [Integer] index the index of the result to fetch
42
+ # @return [DayOne::Entry] the entry
43
+ def [] index
44
+ results[index]
45
+ end
46
+
47
+ private
48
+
49
+ # Caches all journal entries for us. On first running, will load everything
50
+ # from file. After this, will just refer back to the cache.
51
+ # @return [Array] an array of DayOne::Entry objects
52
+ def cache
53
+ if !@cache
54
+ entries = File.join(DayOne::journal_location, 'entries', '*.doentry')
55
+ @cache = Dir[entries].map{ |e| DayOne::EntryImporter::from_file(e).to_entry }
56
+ end
57
+ @cache
58
+ end
59
+ end
data/rb-dayone.gemspec CHANGED
@@ -5,7 +5,7 @@ Gem::Specification.new do |s|
5
5
  s.version = File.read('version.txt')
6
6
 
7
7
  s.summary = "Create DayOne journal entries in ruby."
8
- s.description = "Create [DayOne](http://www.dayoneapp.com) journal entries simply and easily in ruby. Currently only supports text entries, image entries to come."
8
+ s.description = "Create or search [DayOne](http://www.dayoneapp.com) journal entries simply and easily in ruby. Currently only supports text entries, image entries to come."
9
9
 
10
10
  s.author = 'Jan-Yves Ruzicka'
11
11
  s.email = 'janyves.ruzicka@gmail.com'
@@ -19,4 +19,19 @@ Gem::Specification.new do |s|
19
19
 
20
20
  s.add_runtime_dependency 'builder', '~> 2.0'
21
21
  s.add_runtime_dependency 'commander', '~> 4.1.2'
22
+ s.add_runtime_dependency 'libxml-ruby', '~> 2.3.3'
23
+
24
+ s.post_install_message = <<-end
25
+ #{'-'*80}
26
+ Hi there! If you're upgrading from version <= 0.2.0 of this gem, I've been a
27
+ horrid dev and let a few bugs through in my XML building code. In order to fix
28
+ this, you can run `dayone verify` to see if your database needs fixing. If any
29
+ of the errors are my fault, you should be able to fix them with `dayone
30
+ repair`.
31
+
32
+ Sorry if this has caused any inconvenience. If you still have trouble repairing
33
+ any of your .doentry files, send me an email and I'll see what I can do to
34
+ help.
35
+ #{'-'*80}
36
+ end
22
37
  end
@@ -0,0 +1,14 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
+ <plist version="1.0">
4
+ <dict>
5
+ <key>Creation Date</key>
6
+ <date>2012-08-16T08:42:17Z</date>
7
+ <key>Entry Text</key>
8
+ <string>Yes, this is foo.</string>
9
+ <key>Starred</key>
10
+ <false/>
11
+ <key>UUID</key>
12
+ <string>748AD5D252F44149920485B0CEA478E3</string>
13
+ </dict>
14
+ </plist>
@@ -0,0 +1,14 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
+ <plist version="1.0">
4
+ <dict>
5
+ <key>Creation Date</key>
6
+ <date>2012-08-16T08:42:19Z</date>
7
+ <key>Entry Text</key>
8
+ <string>Hello bar.</string>
9
+ <key>Starred</key>
10
+ <true/>
11
+ <key>UUID</key>
12
+ <string>F13723CDFD454481B24312DCD627BFD7</string>
13
+ </dict>
14
+ </plist>
@@ -0,0 +1 @@
1
+ foo
@@ -0,0 +1,12 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
+ <plist version="1.0">
4
+ <dict>
5
+ <key>Entry Text</key>
6
+ <string>Hello, world!</string>
7
+ <key>Starred</key>
8
+ <true/>
9
+ <key>Creation Date</key>
10
+ <date>1997-08-29T02:14:0Z</date>
11
+ </dict>
12
+ </plist>
File without changes
@@ -0,0 +1,12 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
+ <plist version="1.0">
4
+ <dict>
5
+ <key>Entry Text</key>
6
+ <string>æ</string>
7
+ <key>Starred</key>
8
+ <true/>
9
+ <key>Creation Date</key>
10
+ <date>1997-08-29T02:14:0Z</date>
11
+ </dict>
12
+ </plist>
data/spec/dayone_spec.rb CHANGED
@@ -9,7 +9,7 @@ describe DayOne do
9
9
  end
10
10
 
11
11
  def location str
12
- File.join(File.dirname(__FILE__),"locations", "location-#{str}")
12
+ spec_data("locations", "location-#{str}")
13
13
  end
14
14
 
15
15
  it "should return the value given by the +location+ file" do
@@ -0,0 +1,69 @@
1
+ #encoding: UTF-8
2
+
3
+ require './spec/spec_helper'
4
+
5
+ describe DayOne::EntryImporter do
6
+ let(:sample_entry){ DayOne::EntryImporter::from_file spec_data('sample.doentry') }
7
+
8
+ describe "#initialize" do
9
+ it "should accept a string or file" do
10
+ ei = DayOne::EntryImporter.new('foo')
11
+ ei.data.should == 'foo'
12
+
13
+ file_ei = DayOne::EntryImporter::from_file spec_data('foo.doentry')
14
+ file_ei.data.should == 'foo'
15
+ end
16
+ end
17
+
18
+ describe "#[]" do
19
+
20
+ def wrap str
21
+ <<-end
22
+ <plist>
23
+ <dict>
24
+ <key>element</key>
25
+ <string>#{str}</string>
26
+ </dict>
27
+ </plist>
28
+ end
29
+ end
30
+
31
+ it "should parse strings" do
32
+ sample_entry['Entry Text'].should == 'Hello, world!'
33
+ end
34
+
35
+ it "should parse booleans" do
36
+ sample_entry['Starred'].should == true
37
+ end
38
+
39
+ it "should parse dates" do
40
+ sample_entry['Creation Date'].should == Time.new(1997, 8, 29, 2, 14, 0)
41
+ end
42
+
43
+ it "should accept ampersands" do
44
+ importer = DayOne::EntryImporter.new(wrap('&amp;'))
45
+ importer['element'].should == '&'
46
+ end
47
+
48
+ it "should accept UTF-8" do
49
+ importer = DayOne::EntryImporter.new(wrap('æ'))
50
+ importer['element'].should == 'æ'
51
+ end
52
+
53
+ it "should accept UTF-8 from file" do
54
+ importer = DayOne::EntryImporter.from_file spec_data('utf.doentry')
55
+ importer['Entry Text'].should == 'æ'
56
+ end
57
+
58
+ end
59
+
60
+ describe "#to_entry" do
61
+ it "should make a valid entry" do
62
+ entry = sample_entry.to_entry
63
+ entry.entry_text.should == 'Hello, world!'
64
+ entry.starred.should be_true
65
+ entry.creation_date.year.should == 1997
66
+ entry.should be_saved
67
+ end
68
+ end
69
+ end
data/spec/entry_spec.rb CHANGED
@@ -2,12 +2,18 @@ require './spec/spec_helper'
2
2
  require 'fileutils'
3
3
 
4
4
  describe DayOne::Entry do
5
- after :all do
6
- Dir['spec/entries/*.doentry'].each{ |f| FileUtils.rm(f) }
7
- FileUtils.rmdir('spec/entries')
5
+ before :each do
6
+ FileUtils::mkdir_p spec_data('working/entries')
7
+ end
8
+
9
+ after :each do
10
+ FileUtils::rm_rf spec_data('working')
8
11
  end
9
12
 
10
13
  describe "#to_xml" do
14
+
15
+ let(:sample_entry){ DayOne::Entry.new('foo', starred:true) }
16
+
11
17
  it "should give a default entry" do
12
18
  e = subject.to_xml
13
19
  e.should match %r|<key>Entry Text</key>\s*<string></string>|
@@ -15,31 +21,38 @@ describe DayOne::Entry do
15
21
  end
16
22
 
17
23
  it "should set from initialize" do
18
- e = DayOne::Entry.new 'foo', starred:true
19
- e.starred.should be_true
20
- e.entry_text.should == 'foo'
24
+ sample_entry.starred.should be_true
25
+ sample_entry.entry_text.should == 'foo'
26
+ sample_entry.should_not be_saved
21
27
  end
22
28
 
23
29
  it "should act properly when starred" do
24
- e = DayOne::Entry.new('foo', starred:true).to_xml
25
- e.should match %r|<key>Starred</key>\s*<true/>|
30
+ sample_entry.to_xml.should match %r|<key>Starred</key>\s*<true/>|
26
31
  end
27
32
  end
28
33
 
29
34
  describe "#create!" do
30
35
  it "should correctly create a .doentry file" do
31
- DayOne::journal_location = 'spec'
32
- FileUtils::mkdir_p 'spec/entries'
36
+
37
+ DayOne::journal_location = spec_data('working')
33
38
 
34
39
  e = subject
35
40
  e.entry_text = "Hello, world!"
36
41
  e.create!
37
42
 
38
- file_location = Dir['spec/entries/*.doentry'][0]
43
+ file_location = Dir[spec_data('working', 'entries', '*.doentry')][0]
39
44
  file_location.should_not be_nil
40
45
 
41
46
  contents = File.read(file_location)
42
47
  contents.should == e.to_xml
43
48
  end
44
49
  end
50
+
51
+ describe "#xml_valid?" do
52
+ it "should handle weird XML characters" do
53
+ e = subject
54
+ e.entry_text = "Hello <&> Goodbye"
55
+ e.should be_xml_valid
56
+ end
57
+ end
45
58
  end
@@ -13,7 +13,7 @@ describe DayOne::PlistReader do
13
13
  end
14
14
 
15
15
  it "should correctly parse binary plists" do
16
- reader = DayOne::PlistReader.new(File.join(File.dirname(__FILE__),'sample.plist'))
16
+ reader = DayOne::PlistReader.new(File.join(File.dirname(__FILE__),'data', 'sample.plist'))
17
17
  reader['foo'].should == 'bar'
18
18
  end
19
19
  end
@@ -0,0 +1,35 @@
1
+ describe DayOne::Search do
2
+ describe "#initialize" do
3
+ it "should create a Search object, uninitialized" do
4
+ subject.entry_text.should == ''
5
+ subject.starred.should be_nil
6
+ end
7
+ end
8
+
9
+ describe "#results" do
10
+ before :all do
11
+ DayOne::journal_location = spec_data
12
+ end
13
+
14
+ it "should find all posts when no search criteria are applied" do
15
+ subject.results.size.should == 2
16
+ end
17
+
18
+ it "should find posts when searching by string" do
19
+ search = DayOne::Search.new entry_text: 'foo'
20
+ search.results.size.should == 1
21
+ search[0].entry_text.should == "Yes, this is foo."
22
+ end
23
+
24
+ it "should find posts when searching by starred" do
25
+ search = DayOne::Search.new starred:true
26
+ search.results.size.should == 1
27
+ search[0].entry_text.should == "Hello bar."
28
+ end
29
+
30
+ it "should find posts when searching by string and starred" do
31
+ search = DayOne::Search.new entry_text: 'foo', starred:true
32
+ search.results.should be_empty
33
+ end
34
+ end
35
+ end
data/spec/spec_helper.rb CHANGED
@@ -1 +1,5 @@
1
1
  require './lib/rb-dayone'
2
+
3
+ def spec_data *path
4
+ File.join(File.dirname(__FILE__), 'data', *path)
5
+ end
data/version.txt CHANGED
@@ -1 +1 @@
1
- 0.2.0
1
+ 0.3.3
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rb-dayone
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.3
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-08-14 00:00:00.000000000 Z
12
+ date: 2012-08-17 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: builder
@@ -43,8 +43,24 @@ dependencies:
43
43
  - - ~>
44
44
  - !ruby/object:Gem::Version
45
45
  version: 4.1.2
46
- description: Create [DayOne](http://www.dayoneapp.com) journal entries simply and
47
- easily in ruby. Currently only supports text entries, image entries to come.
46
+ - !ruby/object:Gem::Dependency
47
+ name: libxml-ruby
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ~>
52
+ - !ruby/object:Gem::Version
53
+ version: 2.3.3
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: 2.3.3
62
+ description: Create or search [DayOne](http://www.dayoneapp.com) journal entries simply
63
+ and easily in ruby. Currently only supports text entries, image entries to come.
48
64
  email: janyves.ruzicka@gmail.com
49
65
  executables:
50
66
  - dayone
@@ -57,21 +73,37 @@ files:
57
73
  - History.rdoc
58
74
  - lib/rb-dayone.rb
59
75
  - lib/rb-dayone/entry.rb
76
+ - lib/rb-dayone/entry_importer.rb
60
77
  - lib/rb-dayone/plist_reader.rb
78
+ - lib/rb-dayone/search.rb
61
79
  - Manifest
80
+ - Rakefile
62
81
  - rb-dayone.gemspec
63
82
  - README.md
83
+ - spec/data/entries/748AD5D252F44149920485B0CEA478E3.doentry
84
+ - spec/data/entries/F13723CDFD454481B24312DCD627BFD7.doentry
85
+ - spec/data/foo.doentry
86
+ - spec/data/locations/location-auto/location
87
+ - spec/data/locations/location-specified/location
88
+ - spec/data/sample.doentry
89
+ - spec/data/sample.plist
90
+ - spec/data/utf.doentry
64
91
  - spec/dayone_spec.rb
92
+ - spec/entry_importer_spec.rb
65
93
  - spec/entry_spec.rb
66
- - spec/locations/location-auto/location
67
- - spec/locations/location-specified/location
68
- - spec/spec_helper.rb
69
94
  - spec/plist_reader_spec.rb
70
- - spec/sample.plist
95
+ - spec/search_spec.rb
96
+ - spec/spec_helper.rb
71
97
  - version.txt
72
98
  homepage: https://github.com/jyruzicka/rb-dayone
73
99
  licenses: []
74
- post_install_message:
100
+ post_install_message: ! "--------------------------------------------------------------------------------\nHi
101
+ there! If you're upgrading from version <= 0.2.0 of this gem, I've been a\nhorrid
102
+ dev and let a few bugs through in my XML building code. In order to fix\nthis, you
103
+ can run `dayone verify` to see if your database needs fixing. If any \nof the errors
104
+ are my fault, you should be able to fix them with `dayone\nrepair`.\n\nSorry if
105
+ this has caused any inconvenience. If you still have trouble repairing\nany of your
106
+ .doentry files, send me an email and I'll see what I can do to\nhelp.\n--------------------------------------------------------------------------------\n"
75
107
  rdoc_options: []
76
108
  require_paths:
77
109
  - lib