├── .travis.yml ├── Gemfile ├── lib ├── evernote_editor │ ├── version.rb │ └── editor.rb └── evernote_editor.rb ├── Rakefile ├── .gitignore ├── spec ├── spec_helper.rb └── evernote_editor │ └── editor_spec.rb ├── bin └── evned ├── LICENSE.txt ├── README.md └── evernote-editor.gemspec /.travis.yml: -------------------------------------------------------------------------------- 1 | rvm: 2 | - 2.0.0 3 | - 2.1.0 4 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | gemspec 3 | -------------------------------------------------------------------------------- /lib/evernote_editor/version.rb: -------------------------------------------------------------------------------- 1 | module EvernoteEditor 2 | VERSION = "0.1.9" 3 | end 4 | -------------------------------------------------------------------------------- /lib/evernote_editor.rb: -------------------------------------------------------------------------------- 1 | require "evernote_editor/editor" 2 | require "evernote_editor/version" 3 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require "bundler/gem_tasks" 2 | require 'rspec/core/rake_task' 3 | 4 | RSpec::Core::RakeTask.new('spec') 5 | 6 | # If you want to make this the default task 7 | task :default => :spec 8 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.gem 2 | *.rbc 3 | .bundle 4 | .config 5 | .yardoc 6 | Gemfile.lock 7 | InstalledFiles 8 | _yardoc 9 | coverage 10 | doc/ 11 | lib/bundler/man 12 | pkg 13 | rdoc 14 | spec/reports 15 | test/tmp 16 | test/version_tmp 17 | tmp 18 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 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 | config.expect_with :rspec do |c| 11 | c.syntax = :should 12 | end 13 | config.mock_with :rspec do |c| 14 | c.syntax = :should 15 | end 16 | 17 | def write_fakefs_config 18 | File.open(File.expand_path("~/.evned"), 'w') do |f| 19 | f.write( { token: '123', editor: 'vim' }.to_json ) 20 | end 21 | end 22 | end 23 | 24 | -------------------------------------------------------------------------------- /bin/evned: -------------------------------------------------------------------------------- 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 33 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 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. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://travis-ci.org/henrypoydar/evernote-editor.png?branch=master)](https://travis-ci.org/henrypoydar/evernote-editor) 2 | 3 | # Evernote Editor 4 | 5 | Simple gem that provides command line creation and editing of Evernote notes. 6 | Uses your favorite editor and Markdown formatting. 7 | 8 | ## Requirements 9 | 10 | Only tested on OSX and Ruby 2.0, 2.1 with `vim`, `mvim` and `sublime` editors. YMMV. 11 | 12 | ## Installation 13 | 14 | gem install evernote-editor 15 | 16 | ## Usage 17 | 18 | You'll need a developer token (http://dev.evernote.com/start/core/authentication.php#devtoken) 19 | to use this tool. The first time you run it you will be prompted for it. 20 | You will also be prompted for the path to your editor. 21 | You can modify both values later by editing `~/.enved` 22 | 23 | evned [options] title tag1,tag2 24 | -s, --sandbox Use the Evernote sandbox server 25 | -e, --edit Search for and edit an existing note by title 26 | -h, --help Display this screen 27 | 28 | Title is optional on note creation. Tags are ignored when a note is edited. 29 | 30 | ## Development 31 | 32 | bundle 33 | bx rspec spec 34 | -------------------------------------------------------------------------------- /evernote-editor.gemspec: -------------------------------------------------------------------------------- 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.summary = %q{Command line creation and editing of Evernote notes} 13 | gem.description = %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.2.3" 22 | gem.add_runtime_dependency "highline", "~> 1.7" 23 | gem.add_runtime_dependency "redcarpet", "~> 3.2" 24 | gem.add_runtime_dependency "reverse_markdown", "0.8.1" 25 | gem.add_runtime_dependency "sanitize", "3.1" 26 | 27 | gem.add_development_dependency "fakefs", "~> 0.6.7" 28 | gem.add_development_dependency "rake", "~> 10.4" 29 | gem.add_development_dependency "rspec", "~> 3.2" 30 | 31 | end 32 | -------------------------------------------------------------------------------- /lib/evernote_editor/editor.rb: -------------------------------------------------------------------------------- 1 | require 'evernote_oauth' 2 | require 'fileutils' 3 | require 'tempfile' 4 | require "highline/import" 5 | require "json" 6 | require "redcarpet" 7 | require "reverse_markdown" 8 | require "sanitize" 9 | 10 | module EvernoteEditor 11 | 12 | class Editor 13 | 14 | CONFIGURATION_FILE = File.expand_path("~/.evned") 15 | attr_accessor :configuration 16 | 17 | def initialize(*args, opts) 18 | @title = args.flatten[0] || "" 19 | @tags = (args.flatten[1] || '').split(',') 20 | @options = opts 21 | @sandbox = opts[:sandbox] 22 | @mkdout = Redcarpet::Markdown.new(Redcarpet::Render::HTML, 23 | autolink: true, space_after_headers: true, no_intra_emphasis: true) 24 | @notebooks = [] 25 | end 26 | 27 | def run 28 | configure 29 | @options[:edit] ? edit_note : create_note 30 | end 31 | 32 | def configure 33 | FileUtils.touch(CONFIGURATION_FILE) unless File.exist?(CONFIGURATION_FILE) 34 | #@configuration = YAML::load(File.open(CONFIGURATION_FILE)) || {} 35 | @configuration = JSON::load(File.open(CONFIGURATION_FILE)) || {} 36 | #@configuration = JSON.parse( IO.read(CONFIGURATION_FILE) || {} ) 37 | store_key unless @configuration['token'] 38 | store_editor unless @configuration['editor'] 39 | end 40 | 41 | def create_note 42 | markdown = invoke_editor 43 | begin 44 | evn_client = EvernoteOAuth::Client.new(token: @configuration['token'], sandbox: @sandbox) 45 | note_store = evn_client.note_store 46 | note = Evernote::EDAM::Type::Note.new 47 | note.title = @title.empty? ? "Untitled note" : @title 48 | note.tagNames = @tags unless @tags.empty? 49 | note.content = note_markup(markdown) 50 | created_note = note_store.createNote(@configuration['token'], note) 51 | say "Successfully created new note '#{created_note.title}'" 52 | rescue Evernote::EDAM::Error::EDAMSystemException, 53 | Evernote::EDAM::Error::EDAMUserException, 54 | Evernote::EDAM::Error::EDAMNotFoundException => e 55 | say "Sorry, an error occurred saving the note to Evernote (#{e.message})" 56 | graceful_failure(markdown) 57 | end 58 | end 59 | 60 | def graceful_failure(markdown) 61 | say "Here's the markdown you were trying to save:" 62 | say "" 63 | say "--BEGIN--" 64 | say markdown 65 | say "--END--" 66 | say "" 67 | end 68 | 69 | def edit_note 70 | 71 | found_notes = search_notes(@title) 72 | return unless found_notes 73 | if found_notes.empty? 74 | say "No notes were found matching '#{@title}'" 75 | return 76 | end 77 | 78 | choice = choose do |menu| 79 | menu.prompt = "Which note would you like to edit:" 80 | found_notes.each do |n| 81 | menu.choice("#{Time.at(n.updated/1000).strftime('%Y %b %d %H:%M')} [#{lookup_notebook_name(n.notebookGuid)}] #{n.title}") do 82 | n.guid 83 | end 84 | end 85 | menu.choice("None") { nil } 86 | end 87 | return if choice.nil? 88 | 89 | begin 90 | evn_client = EvernoteOAuth::Client.new(token: @configuration['token'], sandbox: @sandbox) 91 | note_store = evn_client.note_store 92 | note = note_store.getNote(@configuration['token'], choice, true, true, false, false) 93 | rescue Evernote::EDAM::Error::EDAMSystemException, 94 | Evernote::EDAM::Error::EDAMUserException, 95 | Evernote::EDAM::Error::EDAMNotFoundException => e 96 | say "Sorry, an error occurred communicating with Evernote (#{e.message})" 97 | return 98 | end 99 | 100 | markdown = invoke_editor(note_markdown(note.content)) 101 | note.content = note_markup(markdown) 102 | note.updated = Time.now.to_i * 1000 103 | 104 | begin 105 | note_store.updateNote(@configuration['token'], note) 106 | say "Successfully updated note '#{note.title}'" 107 | rescue Evernote::EDAM::Error::EDAMSystemException, 108 | Evernote::EDAM::Error::EDAMUserException, 109 | Evernote::EDAM::Error::EDAMNotFoundException => e 110 | say "Sorry, an error occurred saving the note to Evernote (#{e.message})" 111 | graceful_failure(markdown) 112 | end 113 | 114 | end 115 | 116 | def search_notes(term = '') 117 | begin 118 | evn_client = EvernoteOAuth::Client.new(token: @configuration['token'], sandbox: @sandbox) 119 | note_store = evn_client.note_store 120 | note_filter = Evernote::EDAM::NoteStore::NoteFilter.new 121 | note_filter.words = term 122 | results = note_store.findNotes(@configuration['token'], note_filter, 0, 10).notes 123 | rescue Evernote::EDAM::Error::EDAMSystemException, 124 | Evernote::EDAM::Error::EDAMUserException, 125 | Evernote::EDAM::Error::EDAMNotFoundException => e 126 | say "Sorry, an error occurred communicating with Evernote (#{e.inspect})" 127 | false 128 | end 129 | 130 | end 131 | 132 | def note_markup(markdown) 133 | "#{@mkdout.render(markdown)}" 134 | end 135 | 136 | def note_markdown(markup) 137 | markup = Sanitize.clean(markup, Sanitize::Config::RELAXED) 138 | ReverseMarkdown.convert markup.strip 139 | end 140 | 141 | def invoke_editor(initial_content = "") 142 | file = Tempfile.new(['evned', '.markdown']) 143 | file.puts(initial_content) 144 | file.flush 145 | file.close(false) 146 | open_editor(file.path) 147 | content = File.read(file.path) 148 | file.unlink 149 | content 150 | end 151 | 152 | def open_editor(file_path) 153 | cmd = [@configuration['editor'], blocking_flag, file_path].join(' ') 154 | system(cmd) or raise SystemCallError, "`#{cmd}` gave exit status: #{$?.exitstatus}" 155 | end 156 | 157 | # Patterned from Pry 158 | def blocking_flag 159 | case File.basename(@configuration['editor']) 160 | when /^[gm]vim/ 161 | '--nofork' 162 | when /^jedit/ 163 | '-wait' 164 | when /^mate/, /^subl/ 165 | '-w' 166 | end 167 | end 168 | 169 | 170 | def store_key 171 | say "You will need a developer token to use this editor." 172 | say "More information: http://dev.evernote.com/start/core/authentication.php#devtoken" 173 | token = ask("Please enter your developer token: ") { |q| q.default = "none" } 174 | @configuration['token'] = token 175 | write_configuration 176 | end 177 | 178 | def store_editor 179 | editor_command = ask("Please enter the editor command you would like to use: ") { |q| q.default = `which vim`.strip.chomp } 180 | @configuration['editor'] = editor_command 181 | write_configuration 182 | end 183 | 184 | def write_configuration 185 | File.open(CONFIGURATION_FILE, "w") do |file| 186 | file.write @configuration.to_json 187 | end 188 | end 189 | 190 | def lookup_notebook_name(guid) 191 | if @notebooks.empty? 192 | begin 193 | evn_client = EvernoteOAuth::Client.new(token: @configuration['token'], sandbox: @sandbox) 194 | note_store = evn_client.note_store 195 | @notebooks = note_store.listNotebooks 196 | rescue Evernote::EDAM::Error::EDAMSystemException, 197 | Evernote::EDAM::Error::EDAMUserException, 198 | Evernote::EDAM::Error::EDAMNotFoundException => e 199 | return "unknown notebook" 200 | end 201 | end 202 | @notebooks.select {|n| n.guid == guid}.first.name 203 | end 204 | 205 | end 206 | 207 | end 208 | -------------------------------------------------------------------------------- /spec/evernote_editor/editor_spec.rb: -------------------------------------------------------------------------------- 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 | getNotebook: double("notebook", guid: "456", name: "Zebra Notebook"), 11 | listNotebooks: [double("notebook", guid: "456", name: "Zebra Notebook")], 12 | createNote: double("note", guid: "123", title: 'Alpha'), 13 | getNote: double("note", guid: "123", title: 'Alpha', 14 | :content= => nil, :updated= => nil, 15 | content: "\n\n
alpha bravo
"), 16 | :updateNote => nil, 17 | findNotes: double("notes", notes: [ 18 | double("note", title: 'alpha', guid: "123", updated: 1361577921000 ), 19 | double("note", title: 'bravo', guid: "456", updated: 1361577937000 )])) 20 | end 21 | 22 | describe "#configure" do 23 | 24 | let(:enved) { EvernoteEditor::Editor.new('a note', {}) } 25 | 26 | before do 27 | # Silence the spec output 28 | EvernoteEditor::Editor.any_instance.stub(:say) 29 | end 30 | 31 | context "when a configuration dot file does not exist" do 32 | 33 | it "prompts for a developer token" do 34 | enved.should_receive(:ask).with(/token/).and_return('123') 35 | enved.stub(:ask).with(/editor/).and_return('vim') 36 | enved.configure 37 | end 38 | 39 | it "prompts for a editor path" do 40 | enved.stub(:ask).with(/token/).and_return('123') 41 | enved.should_receive(:ask).with(/editor/).and_return('vim') 42 | enved.configure 43 | end 44 | 45 | it "stores the developer token" do 46 | enved.stub(:ask).with(/token/).and_return('123') 47 | enved.stub(:ask).with(/editor/).and_return('vim') 48 | enved.configure 49 | JSON::load(File.open(File.expand_path("~/.evned")))['token'].should eq "123" 50 | end 51 | 52 | it "stores the editor path" do 53 | enved.stub(:ask).with(/token/).and_return('123') 54 | enved.stub(:ask).with(/editor/).and_return('vim') 55 | enved.configure 56 | JSON::load(File.open(File.expand_path("~/.evned")))['editor'].should eq "vim" 57 | end 58 | 59 | end 60 | 61 | context "when a configuration dot file exists" do 62 | 63 | before { write_fakefs_config } 64 | 65 | it "does not prompt for a developer token" do 66 | enved.should_not_receive(:ask).with(/token/) 67 | enved.configure 68 | end 69 | 70 | it "does not prompt for an editor path" do 71 | enved.should_not_receive(:ask).with(/editor/) 72 | enved.configure 73 | end 74 | 75 | end 76 | 77 | context "when a configuration dot file is incomplete/invalid" do 78 | 79 | before do 80 | File.open(File.expand_path("~/.evned"), 'w') do |f| 81 | f.write( { foo: '123', editor: 'vim' }.to_json ) 82 | end 83 | end 84 | 85 | it "prompts for missing information" do 86 | enved.should_receive(:ask).with(/token/).and_return('123') 87 | enved.should_not_receive(:ask).with(/editor/) 88 | enved.configure 89 | end 90 | 91 | it "rewrites the configuration file" do 92 | enved.should_receive(:ask).with(/token/).and_return('123') 93 | enved.configure 94 | JSON::load(File.open(File.expand_path("~/.evned")))['token'].should eq "123" 95 | end 96 | 97 | end 98 | 99 | end 100 | 101 | describe "#create_note" do 102 | 103 | let(:enved) { EvernoteEditor::Editor.new('a note', {}) } 104 | 105 | before do 106 | write_fakefs_config 107 | EvernoteEditor::Editor.any_instance.stub(:say) 108 | end 109 | 110 | it "opens a new document in a text editor" do 111 | enved.should_receive(:open_editor).once 112 | EvernoteOAuth::Client.stub(:new).and_return( 113 | double("EvernoteOAuth::Client", note_store: @mock_note_store)) 114 | enved.configure 115 | enved.create_note 116 | end 117 | 118 | it "saves the document to Evernote" do 119 | enved.stub(:open_editor) 120 | EvernoteOAuth::Client.should_receive(:new).and_return( 121 | double("EvernoteOAuth::Client", note_store: @mock_note_store)) 122 | enved.configure 123 | enved.create_note 124 | end 125 | 126 | context "when there is an Evernote Cloud API communication error" do 127 | 128 | it "prints your note to STDOUT so you don't lose it" do 129 | enved.stub(:open_editor) 130 | EvernoteOAuth::Client.stub(:new).and_raise(Evernote::EDAM::Error::EDAMSystemException) 131 | enved.should_receive(:graceful_failure).once 132 | enved.configure 133 | enved.create_note 134 | end 135 | 136 | end 137 | 138 | end 139 | 140 | describe "#search_notes" do 141 | 142 | before { write_fakefs_config } 143 | let(:enved) { EvernoteEditor::Editor.new('a note', {}) } 144 | 145 | it "returns an array of hashes of notes" do 146 | enved.configure 147 | EvernoteOAuth::Client.stub(:new).and_return( 148 | double("EvernoteOAuth::Client", note_store: @mock_note_store)) 149 | enved.search_notes.first.title.should eq 'alpha' 150 | end 151 | 152 | context "when there is an Evernote Cloud API communication error" do 153 | 154 | it "displays an error message" do 155 | enved.configure 156 | EvernoteOAuth::Client.stub(:new).and_raise(Evernote::EDAM::Error::EDAMSystemException) 157 | enved.should_receive(:say).with(/sorry/i).once 158 | enved.search_notes 159 | end 160 | 161 | it "returns false" do 162 | enved.configure 163 | EvernoteOAuth::Client.stub(:new).and_raise(Evernote::EDAM::Error::EDAMSystemException) 164 | enved.stub(:say) 165 | enved.search_notes.should eq false 166 | end 167 | 168 | end 169 | 170 | end 171 | 172 | describe "#edit_note" do 173 | 174 | before { write_fakefs_config } 175 | let(:enved) { EvernoteEditor::Editor.new('a note', {}) } 176 | 177 | it "presents a list of notes that match the title input" do 178 | EvernoteOAuth::Client.stub(:new).and_return( 179 | double("EvernoteOAuth::Client", note_store: @mock_note_store)) 180 | enved.should_receive(:choose) 181 | enved.stub(:open_editor) 182 | enved.configure 183 | enved.edit_note 184 | end 185 | 186 | context "when the user selects 'none'" do 187 | 188 | it "does note invoke the editor" do 189 | EvernoteOAuth::Client.stub(:new).and_return( 190 | double("EvernoteOAuth::Client", note_store: @mock_note_store)) 191 | enved.stub(:choose).and_return(nil) 192 | enved.should_not_receive(:open_editor) 193 | enved.configure 194 | enved.edit_note 195 | end 196 | 197 | end 198 | 199 | context "when the user selects a note" do 200 | 201 | it "invokes the editor" do 202 | EvernoteOAuth::Client.stub(:new).and_return( 203 | double("EvernoteOAuth::Client", note_store: @mock_note_store)) 204 | enved.stub(:choose).and_return('123') 205 | enved.should_receive(:open_editor).once 206 | enved.stub(:say) 207 | enved.configure 208 | enved.edit_note 209 | end 210 | 211 | it "saves the document to Evernote" do 212 | EvernoteOAuth::Client.stub(:new).and_return( 213 | double("EvernoteOAuth::Client", note_store: @mock_note_store)) 214 | enved.stub(:choose).and_return('123') 215 | enved.stub(:open_editor) 216 | enved.should_receive(:say).with(/Success/) 217 | enved.configure 218 | enved.edit_note 219 | end 220 | 221 | context "when there is an Evernote Cloud API communication error" do 222 | 223 | it "prints your note to STDOUT so you don't lose it" do 224 | @mock_note_store.stub(:updateNote).and_raise(Evernote::EDAM::Error::EDAMSystemException) 225 | EvernoteOAuth::Client.stub(:new).and_return( 226 | double("EvernoteOAuth::Client", note_store: @mock_note_store)) 227 | enved.stub(:choose).and_return('123') 228 | enved.stub(:open_editor) 229 | enved.stub(:say) 230 | enved.should_receive(:graceful_failure).once 231 | enved.configure 232 | enved.edit_note 233 | end 234 | 235 | end 236 | end 237 | 238 | context "when there was an error searching notes" do 239 | 240 | it "does not present a search menu" do 241 | enved.stub(:search_notes).and_return(false) 242 | enved.should_not_receive(:choose) 243 | enved.configure 244 | enved.edit_note 245 | end 246 | 247 | end 248 | 249 | context "when no search results are found" do 250 | 251 | it "tells user no notes were found" do 252 | enved.stub(:search_notes).and_return([]) 253 | enved.should_receive(:say).with(/^No\ notes\ were\ found/) 254 | enved.configure 255 | enved.edit_note 256 | end 257 | 258 | it "does not present a list of notes" do 259 | enved.stub(:search_notes).and_return([]) 260 | enved.stub(:say) 261 | enved.should_not_receive(:choose) 262 | enved.configure 263 | enved.edit_note 264 | end 265 | 266 | end 267 | 268 | end 269 | 270 | describe "#note_markup" do 271 | 272 | let(:enved) { EvernoteEditor::Editor.new('a note', {}) } 273 | 274 | it "converts markdown to XHTML" do 275 | enved.note_markup("This is *bongos*, indeed.").should =~ 276 | /

This is bongos<\/em>, indeed.<\/p>/ 277 | end 278 | 279 | it "inserts XHTML into the ENML" do 280 | enved.note_markup("This is *bongos*, indeed.").should =~ 281 | /\s*

This is bongos<\/em>, indeed.<\/p>\s*<\/en-note>/ 282 | end 283 | 284 | end 285 | 286 | describe "#note_markdown" do 287 | 288 | let(:enved) { EvernoteEditor::Editor.new('a note', {}) } 289 | 290 | it "converts ENML/XHTML to markdown" do 291 | str = "# Interesting!\n\n- Alpha\n- Bravo\n" 292 | markup = enved.note_markup(str) 293 | enved.note_markdown(markup).should eq str 294 | end 295 | 296 | it "converts nested indentation to markdown" do 297 | # pending "https://github.com/xijo/reverse_markdown/issues/29" 298 | str = "# Interesting!\n\n- Alpha\n - Zebra\n - Yankee\n- Bravo\n" 299 | markup = enved.note_markup(str) 300 | enved.note_markdown(markup).should eq str 301 | end 302 | 303 | end 304 | 305 | describe "#lookup_notebook_name" do 306 | 307 | before { write_fakefs_config } 308 | let(:enved) { EvernoteEditor::Editor.new('a note', {}) } 309 | 310 | it "looks up a notebook name by guid" do 311 | enved.configure 312 | EvernoteOAuth::Client.stub(:new).and_return( 313 | double("EvernoteOAuth::Client", note_store: @mock_note_store)) 314 | enved.lookup_notebook_name('456').should eq 'Zebra Notebook' 315 | end 316 | 317 | it "returns 'unknown notebook' when there is a communication error" do 318 | enved.configure 319 | EvernoteOAuth::Client.stub(:new).and_return( 320 | double("EvernoteOAuth::Client", note_store: @mock_note_store)) 321 | @mock_note_store.stub(:listNotebooks).and_raise(Evernote::EDAM::Error::EDAMSystemException) 322 | enved.lookup_notebook_name('456').should eq 'unknown notebook' 323 | end 324 | 325 | it "first looks in locally stored value for the notebook attributes" do 326 | enved.configure 327 | enved.instance_variable_set(:@notebooks, [ 328 | double("notebook", guid: "456", name: "Yankee Notebook"), 329 | double("notebook", guid: "789", name: "Xray Notebook")]) 330 | EvernoteOAuth::Client.should_not_receive(:new) 331 | enved.lookup_notebook_name('456').should eq 'Yankee Notebook' 332 | 333 | end 334 | 335 | end 336 | 337 | end 338 | --------------------------------------------------------------------------------