evernote-editor 0.1.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 +17 -0
- data/Gemfile +2 -0
- data/LICENSE.txt +22 -0
- data/README.md +26 -0
- data/Rakefile +7 -0
- data/bin/.gitkeep +0 -0
- data/bin/evned +32 -0
- data/evernote-editor.gemspec +31 -0
- data/lib/evernote_editor.rb +3 -0
- data/lib/evernote_editor/editor.rb +185 -0
- data/lib/evernote_editor/version.rb +3 -0
- data/spec/evernote_editor/editor_spec.rb +295 -0
- data/spec/spec_helper.rb +16 -0
- metadata +159 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Henry Poydar
|
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.
|
data/README.md
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# Evernote Editor
|
2
|
+
|
3
|
+
Simple gem that provides command line creation and editing of Evernote notes.
|
4
|
+
Uses your favorite editor and Markdown formatting.
|
5
|
+
|
6
|
+
## Installation
|
7
|
+
|
8
|
+
gem install evernote-editor
|
9
|
+
|
10
|
+
## Usage
|
11
|
+
|
12
|
+
You'll need a developer token (http://dev.evernote.com/start/core/authentication.php#devtoken)
|
13
|
+
to use this tool. The first time you run it you will be prompted for it.
|
14
|
+
You will also be prompted for the path to your editor.
|
15
|
+
You can modify both values later by editing `~/.enved`
|
16
|
+
|
17
|
+
evned [options] title tag1,tag2
|
18
|
+
-s, --sandbox Use the Evernote sandbox server
|
19
|
+
-e, --edit Search for and edit an existing note by title
|
20
|
+
-h, --help Display this screen
|
21
|
+
|
22
|
+
## TODO
|
23
|
+
|
24
|
+
* Store tags on creation
|
25
|
+
* Specs are a bit thin. Stubbing/expecting the thrift stuff is cumbersome.
|
26
|
+
* Travis-ify
|
data/Rakefile
ADDED
data/bin/.gitkeep
ADDED
File without changes
|
data/bin/evned
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
lib = File.expand_path(File.dirname(__FILE__) + '/../lib')
|
4
|
+
$LOAD_PATH.unshift(lib) if File.directory?(lib) && !$LOAD_PATH.include?(lib)
|
5
|
+
|
6
|
+
require 'optparse'
|
7
|
+
require 'evernote_editor'
|
8
|
+
|
9
|
+
options = {}
|
10
|
+
OptionParser.new do |opts|
|
11
|
+
opts.banner = "Usage: evned [options] title tag1,tag2"
|
12
|
+
|
13
|
+
options[:edit] = false
|
14
|
+
options[:sandbox] = false
|
15
|
+
|
16
|
+
opts.on( '-s', '--sandbox', 'Use the Evernote sandbox server' ) do
|
17
|
+
options[:sandbox] = true
|
18
|
+
end
|
19
|
+
|
20
|
+
opts.on( '-e', '--edit', 'Search for and edit an existing note by title' ) do
|
21
|
+
options[:edit] = true
|
22
|
+
end
|
23
|
+
|
24
|
+
opts.on( '-h', '--help', 'Display this screen' ) do
|
25
|
+
puts opts
|
26
|
+
exit
|
27
|
+
end
|
28
|
+
|
29
|
+
end.parse!
|
30
|
+
|
31
|
+
enved = EvernoteEditor::Editor.new(ARGV, options)
|
32
|
+
enved.run
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'evernote_editor/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |gem|
|
7
|
+
|
8
|
+
gem.name = "evernote-editor"
|
9
|
+
gem.version = EvernoteEditor::VERSION
|
10
|
+
gem.authors = ["hpoydar"]
|
11
|
+
gem.email = ["henry@poydar.com"]
|
12
|
+
gem.description = %q{Command line creation and editing of Evernote notes}
|
13
|
+
gem.summary = %q{Simple command line creation and editing of Evernote notes in Markdown format with your favorite editor via a gem installed binary}
|
14
|
+
gem.homepage = "https://github.com/hpoydar/evernote-editor"
|
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.require_paths = ["lib"]
|
20
|
+
|
21
|
+
gem.add_runtime_dependency "evernote_oauth", "~> 0.1.6"
|
22
|
+
gem.add_runtime_dependency "highline", "~> 1.6.15"
|
23
|
+
gem.add_runtime_dependency "redcarpet", "~> 2.2.2"
|
24
|
+
gem.add_runtime_dependency "reverse_markdown", "~> 0.4.3"
|
25
|
+
|
26
|
+
gem.add_development_dependency "rspec", "~> 2.12.0"
|
27
|
+
gem.add_development_dependency "fakefs", "~> 0.4.2"
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
|
@@ -0,0 +1,185 @@
|
|
1
|
+
require 'evernote_oauth'
|
2
|
+
require 'fileutils'
|
3
|
+
require 'tempfile'
|
4
|
+
require "highline/import"
|
5
|
+
require "redcarpet"
|
6
|
+
require "reverse_markdown"
|
7
|
+
|
8
|
+
module EvernoteEditor
|
9
|
+
|
10
|
+
class Editor
|
11
|
+
|
12
|
+
CONFIGURATION_FILE = File.expand_path("~/.evned")
|
13
|
+
attr_accessor :configuration
|
14
|
+
|
15
|
+
def initialize(*args, opts)
|
16
|
+
@title = args.flatten[0] || "Untitled note - #{Time.now}"
|
17
|
+
@tags = (args.flatten[1] || '').split(',')
|
18
|
+
@options = opts
|
19
|
+
@mkdout = Redcarpet::Markdown.new(Redcarpet::Render::XHTML,
|
20
|
+
autolink: true, space_after_headers: true, no_intra_emphasis: true)
|
21
|
+
end
|
22
|
+
|
23
|
+
def run
|
24
|
+
configure
|
25
|
+
@options[:edit] ? edit_note : create_note
|
26
|
+
end
|
27
|
+
|
28
|
+
|
29
|
+
def configure
|
30
|
+
FileUtils.touch(CONFIGURATION_FILE) unless File.exist?(CONFIGURATION_FILE)
|
31
|
+
@configuration = YAML::load(File.open(CONFIGURATION_FILE)) || {}
|
32
|
+
store_key unless @configuration[:token]
|
33
|
+
store_editor unless @configuration[:editor]
|
34
|
+
end
|
35
|
+
|
36
|
+
def create_note
|
37
|
+
markdown = invoke_editor
|
38
|
+
begin
|
39
|
+
evn_client = EvernoteOAuth::Client.new(token: @configuration[:token], sandbox: @sandbox)
|
40
|
+
note_store = evn_client.note_store
|
41
|
+
note = Evernote::EDAM::Type::Note.new
|
42
|
+
note.title = @title
|
43
|
+
note.content = note_markup(markdown)
|
44
|
+
created_note = note_store.createNote(@configuration[:token], note)
|
45
|
+
say "Successfully created new note '#{created_note.title}'"
|
46
|
+
rescue Evernote::EDAM::Error::EDAMSystemException,
|
47
|
+
Evernote::EDAM::Error::EDAMUserException,
|
48
|
+
Evernote::EDAM::Error::EDAMNotFoundException => e
|
49
|
+
say "Sorry, an error occurred saving the note to Evernote (#{e.message})"
|
50
|
+
graceful_failure(markdown)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def graceful_failure(markdown)
|
55
|
+
say "Here's the markdown you were trying to save:"
|
56
|
+
say ""
|
57
|
+
say "--BEGIN--"
|
58
|
+
say markdown
|
59
|
+
say "--END--"
|
60
|
+
say ""
|
61
|
+
end
|
62
|
+
|
63
|
+
def edit_note
|
64
|
+
|
65
|
+
found_notes = search_notes
|
66
|
+
return unless found_notes
|
67
|
+
if found_notes.empty?
|
68
|
+
say "No notes were found matching '#{@title}'"
|
69
|
+
return
|
70
|
+
end
|
71
|
+
|
72
|
+
choice = choose do |menu|
|
73
|
+
menu.prompt = "Which note would you like to edit:"
|
74
|
+
found_notes.each do |n|
|
75
|
+
menu.choice("#{Time.at(n.updated/1000).strftime('%Y-%m-%d %H:%M')} #{n.title}") do
|
76
|
+
n.guid
|
77
|
+
end
|
78
|
+
end
|
79
|
+
menu.choice("None") { nil }
|
80
|
+
end
|
81
|
+
return if choice.nil?
|
82
|
+
|
83
|
+
begin
|
84
|
+
evn_client = EvernoteOAuth::Client.new(token: @configuration[:token], sandbox: @sandbox)
|
85
|
+
note_store = evn_client.note_store
|
86
|
+
note = note_store.getNote(@configuration[:token], choice, true, true, false, false)
|
87
|
+
rescue Evernote::EDAM::Error::EDAMSystemException,
|
88
|
+
Evernote::EDAM::Error::EDAMUserException,
|
89
|
+
Evernote::EDAM::Error::EDAMNotFoundException => e
|
90
|
+
say "Sorry, an error occurred communicating with Evernote (#{e.message})"
|
91
|
+
return
|
92
|
+
end
|
93
|
+
|
94
|
+
markdown = invoke_editor(note_markdown(note.content))
|
95
|
+
note.content = note_markup(markdown)
|
96
|
+
note.updated = Time.now.to_i * 1000
|
97
|
+
|
98
|
+
begin
|
99
|
+
note_store.updateNote(@configuration[:token], note)
|
100
|
+
say "Successfully updated note '#{note.title}'"
|
101
|
+
rescue Evernote::EDAM::Error::EDAMSystemException,
|
102
|
+
Evernote::EDAM::Error::EDAMUserException,
|
103
|
+
Evernote::EDAM::Error::EDAMNotFoundException => e
|
104
|
+
say "Sorry, an error occurred saving the note to Evernote (#{e.message})"
|
105
|
+
graceful_failure(markdown)
|
106
|
+
end
|
107
|
+
|
108
|
+
end
|
109
|
+
|
110
|
+
def search_notes(term = '')
|
111
|
+
begin
|
112
|
+
evn_client = EvernoteOAuth::Client.new(token: @configuration[:token], sandbox: @sandbox)
|
113
|
+
note_store = evn_client.note_store
|
114
|
+
note_filter = Evernote::EDAM::NoteStore::NoteFilter.new
|
115
|
+
note_filter.words = term
|
116
|
+
results = note_store.findNotes(@configuration[:token], note_filter, 0, 10).notes
|
117
|
+
rescue Evernote::EDAM::Error::EDAMSystemException,
|
118
|
+
Evernote::EDAM::Error::EDAMUserException,
|
119
|
+
Evernote::EDAM::Error::EDAMNotFoundException => e
|
120
|
+
say "Sorry, an error occurred saving the note to Evernote (#{e.message})"
|
121
|
+
false
|
122
|
+
end
|
123
|
+
|
124
|
+
end
|
125
|
+
|
126
|
+
def note_markup(markdown)
|
127
|
+
"<?xml version='1.0' encoding='UTF-8'?><!DOCTYPE en-note SYSTEM 'http://xml.evernote.com/pub/enml2.dtd'><en-note>#{@mkdout.render(markdown)}</en-note>"
|
128
|
+
end
|
129
|
+
|
130
|
+
def note_markdown(markup)
|
131
|
+
ReverseMarkdown.parse markup
|
132
|
+
end
|
133
|
+
|
134
|
+
def invoke_editor(initial_content = "")
|
135
|
+
file = Tempfile.new(['evned', '.markdown'])
|
136
|
+
file.puts(initial_content)
|
137
|
+
file.flush
|
138
|
+
file.close(false)
|
139
|
+
open_editor(file.path)
|
140
|
+
content = File.read(file.path)
|
141
|
+
file.unlink
|
142
|
+
content
|
143
|
+
end
|
144
|
+
|
145
|
+
def open_editor(file_path)
|
146
|
+
cmd = [@configuration[:editor], blocking_flag, file_path].join(' ')
|
147
|
+
system(cmd) or raise SystemCallError, "`#{cmd}` gave exit status: #{$?.exitstatus}"
|
148
|
+
end
|
149
|
+
|
150
|
+
# Patterned from Pry
|
151
|
+
def blocking_flag
|
152
|
+
case File.basename(@configuration[:editor])
|
153
|
+
when /^[gm]vim/
|
154
|
+
'--nofork'
|
155
|
+
when /^jedit/
|
156
|
+
'-wait'
|
157
|
+
when /^mate/, /^subl/
|
158
|
+
'-w'
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
|
163
|
+
def store_key
|
164
|
+
say "You will need a developer token to use this editor."
|
165
|
+
say "More information: http://dev.evernote.com/start/core/authentication.php#devtoken"
|
166
|
+
token = ask("Please enter your developer token: ") { |q| q.default = "none" }
|
167
|
+
@configuration[:token] = token
|
168
|
+
write_configuration
|
169
|
+
end
|
170
|
+
|
171
|
+
def store_editor
|
172
|
+
editor_command = ask("Please enter the editor command you would like to use: ") { |q| q.default = `which vim`.strip.chomp }
|
173
|
+
@configuration[:editor] = editor_command
|
174
|
+
write_configuration
|
175
|
+
end
|
176
|
+
|
177
|
+
def write_configuration
|
178
|
+
File.open(CONFIGURATION_FILE, "w") do |file|
|
179
|
+
file.write @configuration.to_yaml
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
end
|
184
|
+
|
185
|
+
end
|
@@ -0,0 +1,295 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe EvernoteEditor::Editor do
|
4
|
+
|
5
|
+
before do
|
6
|
+
# Make sure the necessary paths exist in our fakefs fake file system
|
7
|
+
FileUtils.mkpath(File.expand_path("~"))
|
8
|
+
FileUtils.mkpath(File.expand_path("/tmp"))
|
9
|
+
@mock_note_store = double("note_store",
|
10
|
+
createNote: double("note", guid: "123", title: 'Alpha'),
|
11
|
+
getNote: double("note", guid: "123", title: 'Alpha',
|
12
|
+
:content= => nil, :updated= => nil,
|
13
|
+
content: "<?xml version=\"2.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE en-note SYSTEM \"http://xml.evernote.com/pub/enml2.dtd\">\n<en-note><div>alpha bravo</div></en-note>"),
|
14
|
+
:updateNote => nil,
|
15
|
+
findNotes: double("notes", notes: [
|
16
|
+
double("note", title: 'alpha', guid: "123", updated: 1361577921000 ),
|
17
|
+
double("note", title: 'bravo', guid: "456", updated: 1361577937000 )]))
|
18
|
+
end
|
19
|
+
|
20
|
+
describe "#configure" do
|
21
|
+
|
22
|
+
let(:enved) { EvernoteEditor::Editor.new('a note', {}) }
|
23
|
+
|
24
|
+
before do
|
25
|
+
# Silence the spec output
|
26
|
+
EvernoteEditor::Editor.any_instance.stub(:say)
|
27
|
+
end
|
28
|
+
|
29
|
+
context "when a configuration dot file does not exist" do
|
30
|
+
|
31
|
+
it "prompts for a developer token" do
|
32
|
+
enved.should_receive(:ask).with(/token/).and_return('123')
|
33
|
+
enved.stub(:ask).with(/editor/).and_return('vim')
|
34
|
+
enved.configure
|
35
|
+
end
|
36
|
+
|
37
|
+
it "prompts for a editor path" do
|
38
|
+
enved.stub(:ask).with(/token/).and_return('123')
|
39
|
+
enved.should_receive(:ask).with(/editor/).and_return('vim')
|
40
|
+
enved.configure
|
41
|
+
end
|
42
|
+
|
43
|
+
it "stores the developer token" do
|
44
|
+
enved.stub(:ask).with(/token/).and_return('123')
|
45
|
+
enved.stub(:ask).with(/editor/).and_return('vim')
|
46
|
+
enved.configure
|
47
|
+
YAML::load(File.open(File.expand_path("~/.evned")))[:token].should eq "123"
|
48
|
+
end
|
49
|
+
|
50
|
+
it "stores the editor path" do
|
51
|
+
enved.stub(:ask).with(/token/).and_return('123')
|
52
|
+
enved.stub(:ask).with(/editor/).and_return('vim')
|
53
|
+
enved.configure
|
54
|
+
YAML::load(File.open(File.expand_path("~/.evned")))[:editor].should eq "vim"
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
|
59
|
+
context "when a configuration dot file exists" do
|
60
|
+
|
61
|
+
before { write_fakefs_config }
|
62
|
+
|
63
|
+
it "does not prompt for a developer token" do
|
64
|
+
enved.should_not_receive(:ask).with(/token/)
|
65
|
+
enved.configure
|
66
|
+
end
|
67
|
+
|
68
|
+
it "does not prompt for an editor path" do
|
69
|
+
enved.should_not_receive(:ask).with(/editor/)
|
70
|
+
enved.configure
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
74
|
+
|
75
|
+
context "when a configuration dot file is incomplete/invalid" do
|
76
|
+
|
77
|
+
before do
|
78
|
+
File.open(File.expand_path("~/.evned"), 'w') do |f|
|
79
|
+
f.write( { foo: '123', editor: 'vim' }.to_yaml )
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
it "prompts for missing information" do
|
84
|
+
enved.should_receive(:ask).with(/token/).and_return('123')
|
85
|
+
enved.should_not_receive(:ask).with(/editor/)
|
86
|
+
enved.configure
|
87
|
+
end
|
88
|
+
|
89
|
+
it "rewrites the configuration file" do
|
90
|
+
enved.should_receive(:ask).with(/token/).and_return('123')
|
91
|
+
enved.configure
|
92
|
+
YAML::load(File.open(File.expand_path("~/.evned")))[:token].should eq "123"
|
93
|
+
end
|
94
|
+
|
95
|
+
end
|
96
|
+
|
97
|
+
end
|
98
|
+
|
99
|
+
describe "#create_note" do
|
100
|
+
|
101
|
+
let(:enved) { EvernoteEditor::Editor.new('a note', {}) }
|
102
|
+
|
103
|
+
before do
|
104
|
+
write_fakefs_config
|
105
|
+
EvernoteEditor::Editor.any_instance.stub(:say)
|
106
|
+
end
|
107
|
+
|
108
|
+
it "opens a new document in a text editor" do
|
109
|
+
enved.should_receive(:open_editor).once
|
110
|
+
EvernoteOAuth::Client.stub(:new).and_return(
|
111
|
+
double("EvernoteOAuth::Client", note_store: @mock_note_store))
|
112
|
+
enved.configure
|
113
|
+
enved.create_note
|
114
|
+
end
|
115
|
+
|
116
|
+
it "saves the document to Evernote" do
|
117
|
+
enved.stub!(:open_editor)
|
118
|
+
EvernoteOAuth::Client.should_receive(:new).and_return(
|
119
|
+
double("EvernoteOAuth::Client", note_store: @mock_note_store))
|
120
|
+
enved.configure
|
121
|
+
enved.create_note
|
122
|
+
end
|
123
|
+
|
124
|
+
context "when there is an Evernote Cloud API communication error" do
|
125
|
+
|
126
|
+
it "prints your note to STDOUT so you don't lose it" do
|
127
|
+
enved.stub!(:open_editor)
|
128
|
+
EvernoteOAuth::Client.stub(:new).and_raise(Evernote::EDAM::Error::EDAMSystemException)
|
129
|
+
enved.should_receive(:graceful_failure).once
|
130
|
+
enved.configure
|
131
|
+
enved.create_note
|
132
|
+
end
|
133
|
+
|
134
|
+
end
|
135
|
+
|
136
|
+
end
|
137
|
+
|
138
|
+
describe "#search_notes" do
|
139
|
+
|
140
|
+
before { write_fakefs_config }
|
141
|
+
let(:enved) { EvernoteEditor::Editor.new('a note', {}) }
|
142
|
+
|
143
|
+
it "returns an array of hashes of notes" do
|
144
|
+
enved.configure
|
145
|
+
EvernoteOAuth::Client.stub(:new).and_return(
|
146
|
+
double("EvernoteOAuth::Client", note_store: @mock_note_store))
|
147
|
+
enved.search_notes.first.title.should eq 'alpha'
|
148
|
+
end
|
149
|
+
|
150
|
+
context "when there is an Evernote Cloud API communication error" do
|
151
|
+
|
152
|
+
it "displays an error message" do
|
153
|
+
enved.configure
|
154
|
+
EvernoteOAuth::Client.stub(:new).and_raise(Evernote::EDAM::Error::EDAMSystemException)
|
155
|
+
enved.should_receive(:say).with(/sorry/i).once
|
156
|
+
enved.search_notes
|
157
|
+
end
|
158
|
+
|
159
|
+
it "returns false" do
|
160
|
+
enved.configure
|
161
|
+
EvernoteOAuth::Client.stub(:new).and_raise(Evernote::EDAM::Error::EDAMSystemException)
|
162
|
+
enved.stub(:say)
|
163
|
+
enved.search_notes.should eq false
|
164
|
+
end
|
165
|
+
|
166
|
+
end
|
167
|
+
|
168
|
+
end
|
169
|
+
|
170
|
+
describe "#edit_note" do
|
171
|
+
|
172
|
+
before { write_fakefs_config }
|
173
|
+
let(:enved) { EvernoteEditor::Editor.new('a note', {}) }
|
174
|
+
|
175
|
+
it "presents a list of notes that match the title input" do
|
176
|
+
EvernoteOAuth::Client.stub(:new).and_return(
|
177
|
+
double("EvernoteOAuth::Client", note_store: @mock_note_store))
|
178
|
+
enved.should_receive(:choose)
|
179
|
+
enved.stub(:open_editor)
|
180
|
+
enved.configure
|
181
|
+
enved.edit_note
|
182
|
+
end
|
183
|
+
|
184
|
+
context "when the user selects 'none'" do
|
185
|
+
|
186
|
+
it "does note invoke the editor" do
|
187
|
+
EvernoteOAuth::Client.stub(:new).and_return(
|
188
|
+
double("EvernoteOAuth::Client", note_store: @mock_note_store))
|
189
|
+
enved.stub(:choose).and_return(nil)
|
190
|
+
enved.should_not_receive(:open_editor)
|
191
|
+
enved.configure
|
192
|
+
enved.edit_note
|
193
|
+
end
|
194
|
+
|
195
|
+
end
|
196
|
+
|
197
|
+
context "when the user selects a note" do
|
198
|
+
|
199
|
+
it "invokes the editor" do
|
200
|
+
EvernoteOAuth::Client.stub(:new).and_return(
|
201
|
+
double("EvernoteOAuth::Client", note_store: @mock_note_store))
|
202
|
+
enved.stub(:choose).and_return('123')
|
203
|
+
enved.should_receive(:open_editor).once
|
204
|
+
enved.stub(:say)
|
205
|
+
enved.configure
|
206
|
+
enved.edit_note
|
207
|
+
end
|
208
|
+
|
209
|
+
it "saves the document to Evernote" do
|
210
|
+
EvernoteOAuth::Client.stub(:new).and_return(
|
211
|
+
double("EvernoteOAuth::Client", note_store: @mock_note_store))
|
212
|
+
enved.stub(:choose).and_return('123')
|
213
|
+
enved.stub(:open_editor)
|
214
|
+
enved.should_receive(:say).with(/Success/)
|
215
|
+
enved.configure
|
216
|
+
enved.edit_note
|
217
|
+
end
|
218
|
+
|
219
|
+
context "when there is an Evernote Cloud API communication error" do
|
220
|
+
|
221
|
+
it "prints your note to STDOUT so you don't lose it" do
|
222
|
+
@mock_note_store.stub(:updateNote).and_raise(Evernote::EDAM::Error::EDAMSystemException)
|
223
|
+
EvernoteOAuth::Client.stub(:new).and_return(
|
224
|
+
double("EvernoteOAuth::Client", note_store: @mock_note_store))
|
225
|
+
enved.stub(:choose).and_return('123')
|
226
|
+
enved.stub(:open_editor)
|
227
|
+
enved.stub(:say)
|
228
|
+
enved.should_receive(:graceful_failure).once
|
229
|
+
enved.configure
|
230
|
+
enved.edit_note
|
231
|
+
end
|
232
|
+
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
context "when there was an error searching notes" do
|
237
|
+
|
238
|
+
it "does not present a search menu" do
|
239
|
+
enved.stub(:search_notes).and_return(false)
|
240
|
+
enved.should_not_receive(:choose)
|
241
|
+
enved.configure
|
242
|
+
enved.edit_note
|
243
|
+
end
|
244
|
+
|
245
|
+
end
|
246
|
+
|
247
|
+
context "when no search results are found" do
|
248
|
+
|
249
|
+
it "tells user no notes were found" do
|
250
|
+
enved.stub(:search_notes).and_return([])
|
251
|
+
enved.should_receive(:say).with(/^No\ notes\ were\ found/)
|
252
|
+
enved.configure
|
253
|
+
enved.edit_note
|
254
|
+
end
|
255
|
+
|
256
|
+
it "does not present a list of notes" do
|
257
|
+
enved.stub(:search_notes).and_return([])
|
258
|
+
enved.stub(:say)
|
259
|
+
enved.should_not_receive(:choose)
|
260
|
+
enved.configure
|
261
|
+
enved.edit_note
|
262
|
+
end
|
263
|
+
|
264
|
+
end
|
265
|
+
|
266
|
+
end
|
267
|
+
|
268
|
+
describe "#note_markup" do
|
269
|
+
|
270
|
+
let(:enved) { EvernoteEditor::Editor.new('a note', {}) }
|
271
|
+
|
272
|
+
it "converts markdown to XHTML" do
|
273
|
+
enved.note_markup("This is *bongos*, indeed.").should =~
|
274
|
+
/<p>This is <em>bongos<\/em>, indeed.<\/p>/
|
275
|
+
end
|
276
|
+
|
277
|
+
it "inserts XHTML into the ENML" do
|
278
|
+
enved.note_markup("This is *bongos*, indeed.").should =~
|
279
|
+
/<en-note>\s*<p>This is <em>bongos<\/em>, indeed.<\/p>\s*<\/en-note>/
|
280
|
+
end
|
281
|
+
|
282
|
+
end
|
283
|
+
|
284
|
+
describe "#note_markdown" do
|
285
|
+
|
286
|
+
let(:enved) { EvernoteEditor::Editor.new('a note', {}) }
|
287
|
+
|
288
|
+
it "converts ENML/XHTML to markdown" do
|
289
|
+
str = "\n# Interesting!\n\n- Alpha\n- Bravo\n"
|
290
|
+
markup = enved.note_markup(str)
|
291
|
+
enved.note_markdown(markup).should eq str
|
292
|
+
end
|
293
|
+
|
294
|
+
end
|
295
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler/setup'
|
3
|
+
require 'fakefs/spec_helpers'
|
4
|
+
|
5
|
+
require 'evernote_editor'
|
6
|
+
|
7
|
+
RSpec.configure do |config|
|
8
|
+
config.include FakeFS::SpecHelpers
|
9
|
+
|
10
|
+
def write_fakefs_config
|
11
|
+
File.open(File.expand_path("~/.evned"), 'w') do |f|
|
12
|
+
f.write( { token: '123', editor: 'vim' }.to_yaml )
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
metadata
ADDED
@@ -0,0 +1,159 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: evernote-editor
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- hpoydar
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-02-23 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: evernote_oauth
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 0.1.6
|
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.1.6
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: highline
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ~>
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: 1.6.15
|
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: 1.6.15
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: redcarpet
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ~>
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: 2.2.2
|
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.2.2
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: reverse_markdown
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ~>
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: 0.4.3
|
70
|
+
type: :runtime
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ~>
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: 0.4.3
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: rspec
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ~>
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: 2.12.0
|
86
|
+
type: :development
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ~>
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: 2.12.0
|
94
|
+
- !ruby/object:Gem::Dependency
|
95
|
+
name: fakefs
|
96
|
+
requirement: !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
98
|
+
requirements:
|
99
|
+
- - ~>
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: 0.4.2
|
102
|
+
type: :development
|
103
|
+
prerelease: false
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ~>
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: 0.4.2
|
110
|
+
description: Command line creation and editing of Evernote notes
|
111
|
+
email:
|
112
|
+
- henry@poydar.com
|
113
|
+
executables:
|
114
|
+
- .gitkeep
|
115
|
+
- evned
|
116
|
+
extensions: []
|
117
|
+
extra_rdoc_files: []
|
118
|
+
files:
|
119
|
+
- .gitignore
|
120
|
+
- Gemfile
|
121
|
+
- LICENSE.txt
|
122
|
+
- README.md
|
123
|
+
- Rakefile
|
124
|
+
- bin/.gitkeep
|
125
|
+
- bin/evned
|
126
|
+
- evernote-editor.gemspec
|
127
|
+
- lib/evernote_editor.rb
|
128
|
+
- lib/evernote_editor/editor.rb
|
129
|
+
- lib/evernote_editor/version.rb
|
130
|
+
- spec/evernote_editor/editor_spec.rb
|
131
|
+
- spec/spec_helper.rb
|
132
|
+
homepage: https://github.com/hpoydar/evernote-editor
|
133
|
+
licenses: []
|
134
|
+
post_install_message:
|
135
|
+
rdoc_options: []
|
136
|
+
require_paths:
|
137
|
+
- lib
|
138
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
139
|
+
none: false
|
140
|
+
requirements:
|
141
|
+
- - ! '>='
|
142
|
+
- !ruby/object:Gem::Version
|
143
|
+
version: '0'
|
144
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
145
|
+
none: false
|
146
|
+
requirements:
|
147
|
+
- - ! '>='
|
148
|
+
- !ruby/object:Gem::Version
|
149
|
+
version: '0'
|
150
|
+
requirements: []
|
151
|
+
rubyforge_project:
|
152
|
+
rubygems_version: 1.8.23
|
153
|
+
signing_key:
|
154
|
+
specification_version: 3
|
155
|
+
summary: Simple command line creation and editing of Evernote notes in Markdown format
|
156
|
+
with your favorite editor via a gem installed binary
|
157
|
+
test_files:
|
158
|
+
- spec/evernote_editor/editor_spec.rb
|
159
|
+
- spec/spec_helper.rb
|