rb-dayone 0.2.0 → 0.3.3

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/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