expandsync 0.1.3 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +1 -2
- data/Gemfile.lock +7 -5
- data/Rakefile +33 -21
- data/bin/expandsync +37 -9
- data/expandsync.gemspec +2 -1
- data/features/step_definitions/expandsync_steps.rb +2 -2
- data/lib/expandsync/atext.rb +55 -60
- data/lib/expandsync/{version.rb → constants.rb} +6 -1
- data/lib/expandsync/textexpander.rb +142 -157
- data/lib/expandsync.rb +3 -2
- metadata +17 -4
- data/lib/expandsync/cli_message.rb +0 -215
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f68be2f33e8ccba10bca1ccdbe3d22f209256b48
|
4
|
+
data.tar.gz: d93f58763fb2d3c44a66c9ec44402c707fc24bff
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8704dd2a387a22cd156083dab719f77c6c1d2b2d523007b40e94ec42e4ad96e3fb58501080439e655de53349ecba8b23c8693e1cc8992b17d8fd22b52dbfd6c0
|
7
|
+
data.tar.gz: bbca23f9cd02b41f6189184e2e8fb346ddc1697c4d1e5b6dcf8dfd7fda1076434e4aaeb3e630756b334a6da7f8621a34290d178292827692fa1f2665b45abeda
|
data/.travis.yml
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
expandsync (0.
|
4
|
+
expandsync (0.2.0)
|
5
|
+
cliutils
|
5
6
|
methadone (~> 1.3, >= 1.3.1)
|
6
7
|
nokogiri (~> 1.6, >= 1.6.1)
|
7
8
|
|
@@ -15,21 +16,22 @@ GEM
|
|
15
16
|
builder (3.2.2)
|
16
17
|
childprocess (0.5.1)
|
17
18
|
ffi (~> 1.0, >= 1.0.11)
|
18
|
-
|
19
|
+
cliutils (1.1.0)
|
20
|
+
cucumber (1.3.12)
|
19
21
|
builder (>= 2.1.2)
|
20
22
|
diff-lcs (>= 1.1.3)
|
21
23
|
gherkin (~> 2.12)
|
22
24
|
multi_json (>= 1.7.5, < 2.0)
|
23
|
-
multi_test (>= 0.
|
25
|
+
multi_test (>= 0.1.1)
|
24
26
|
diff-lcs (1.2.5)
|
25
27
|
ffi (1.9.3)
|
26
28
|
gherkin (2.12.2)
|
27
29
|
multi_json (~> 1.3)
|
28
30
|
methadone (1.3.2)
|
29
31
|
bundler
|
30
|
-
mini_portile (0.5.
|
32
|
+
mini_portile (0.5.3)
|
31
33
|
multi_json (1.9.0)
|
32
|
-
multi_test (0.
|
34
|
+
multi_test (0.1.1)
|
33
35
|
nokogiri (1.6.1)
|
34
36
|
mini_portile (~> 0.5.0)
|
35
37
|
rake (0.9.6)
|
data/Rakefile
CHANGED
@@ -1,39 +1,51 @@
|
|
1
1
|
require 'rake/clean'
|
2
2
|
require 'rubygems'
|
3
|
-
|
4
|
-
|
5
|
-
|
3
|
+
|
4
|
+
def version
|
5
|
+
contents = File.read File.expand_path('../lib/expandsync/constants.rb', __FILE__)
|
6
|
+
contents[/\sVERSION = '([^']+)'/, 1]
|
7
|
+
end
|
8
|
+
|
6
9
|
spec = eval(File.read('expandsync.gemspec'))
|
7
10
|
|
8
|
-
|
11
|
+
require 'rake/testtask'
|
12
|
+
desc 'Run unit tests'
|
13
|
+
Rake::TestTask.new do |t|
|
14
|
+
t.libs << "test"
|
15
|
+
t.test_files = FileList['test/*_test.rb']
|
9
16
|
end
|
10
17
|
|
18
|
+
require 'cucumber'
|
19
|
+
require 'cucumber/rake/task'
|
11
20
|
CUKE_RESULTS = 'results.html'
|
12
21
|
CLEAN << CUKE_RESULTS
|
13
|
-
|
14
|
-
desc 'Run features'
|
22
|
+
desc 'Run Cucumber features'
|
15
23
|
Cucumber::Rake::Task.new(:features) do |t|
|
16
|
-
opts = "features --format html -o #{CUKE_RESULTS} --format
|
24
|
+
opts = "features --format html -o #{CUKE_RESULTS} --format progress -x"
|
17
25
|
opts += " --tags #{ENV['TAGS']}" if ENV['TAGS']
|
18
26
|
t.cucumber_opts = opts
|
19
27
|
t.fork = false
|
20
28
|
end
|
21
29
|
|
22
|
-
desc
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
30
|
+
desc "Release ExpandSync version #{ version }"
|
31
|
+
task :release => :build do
|
32
|
+
unless `git branch` =~ /^\* master$/
|
33
|
+
puts "You must be on the master branch to release!"
|
34
|
+
exit!
|
35
|
+
end
|
36
|
+
|
37
|
+
sh "git commit --allow-empty -a -m 'Release #{ version }'"
|
38
|
+
sh "git tag v#{ version }"
|
39
|
+
sh "git push origin master"
|
40
|
+
sh "git push origin v#{ version }"
|
41
|
+
sh "gem push pkg/expandsync-#{ version }.gem"
|
28
42
|
end
|
29
43
|
|
30
|
-
|
31
|
-
task
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
t.libs << "test"
|
36
|
-
t.test_files = FileList['test/*_test.rb']
|
44
|
+
desc "Build the gem"
|
45
|
+
task :build do
|
46
|
+
FileUtils.mkdir_p "pkg"
|
47
|
+
sh "gem build expandsync.gemspec"
|
48
|
+
FileUtils.mv("./expandsync-#{ version }.gem", "pkg")
|
37
49
|
end
|
38
50
|
|
39
|
-
task :default => [:test
|
51
|
+
task :default => [:test, :features]
|
data/bin/expandsync
CHANGED
@@ -1,20 +1,48 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
-
|
3
|
-
|
2
|
+
# Encoding: utf-8
|
3
|
+
#--------------------------------------------------------------------
|
4
|
+
# ExpandSync
|
5
|
+
#
|
6
|
+
# Synchronizes text expansion snippets between aText and
|
7
|
+
# TextExpander Touch
|
8
|
+
#
|
9
|
+
# Copyright (c) 2014
|
10
|
+
# Aaron Bach <bachya1208@gmail.com>
|
11
|
+
#
|
12
|
+
# Permission is hereby granted, free of charge, to any person
|
13
|
+
# obtaining a copy of this software and associated documentation
|
14
|
+
# files (the "Software"), to deal in the Software without
|
15
|
+
# restriction, including without limitation the rights to use,
|
16
|
+
# copy, modify, merge, publish, distribute, sublicense, and/or sell
|
17
|
+
# copies of the Software, and to permit persons to whom the
|
18
|
+
# Software is furnished to do so, subject to the following
|
19
|
+
# conditions:
|
20
|
+
#
|
21
|
+
# The above copyright notice and this permission notice shall be
|
22
|
+
# included in all copies or substantial portions of the Software.
|
23
|
+
#
|
24
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
25
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
26
|
+
# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
27
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
28
|
+
# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
29
|
+
# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
30
|
+
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
31
|
+
# OTHER DEALINGS IN THE SOFTWARE.
|
32
|
+
#--------------------------------------------------------------------
|
33
|
+
require 'cliutils'
|
4
34
|
require 'expandsync'
|
5
|
-
require 'fileutils'
|
6
35
|
require 'methadone'
|
7
|
-
require 'nokogiri'
|
8
36
|
require 'optparse'
|
9
37
|
|
10
38
|
class App
|
39
|
+
include CLIUtils::Messenging
|
11
40
|
include Methadone::Main
|
12
|
-
include Methadone::CLILogging
|
13
41
|
|
14
42
|
main do |atext_filepath|
|
15
43
|
begin
|
16
|
-
atext = AText.new(atext_filepath, options[:a])
|
17
|
-
textexpander = TextExpander.new
|
44
|
+
atext = ExpandSync::AText.new(atext_filepath, options[:a])
|
45
|
+
textexpander = ExpandSync::TextExpander.new
|
18
46
|
|
19
47
|
# Create file content (CSV for aText, XML for TextExpander)
|
20
48
|
# that contains the correct data:
|
@@ -36,7 +64,7 @@ class App
|
|
36
64
|
# This has to be here so that my Cucumber Aruba tests work. Don't ask why.
|
37
65
|
leak_exceptions(true)
|
38
66
|
rescue StandardError => e
|
39
|
-
|
67
|
+
messenger.error(e.to_s)
|
40
68
|
exit!(1)
|
41
69
|
end
|
42
70
|
end
|
@@ -45,7 +73,7 @@ class App
|
|
45
73
|
version ExpandSync::VERSION
|
46
74
|
|
47
75
|
# Flags & Switches
|
48
|
-
on('-a FILEPATH', "Output location for aText rules (defaults to ~/#{ AText::OUTPUT_FILENAME })")
|
76
|
+
on('-a FILEPATH', "Output location for aText rules (defaults to ~/#{ ExpandSync::AText::OUTPUT_FILENAME })")
|
49
77
|
on('-n', 'Disable backing up of Settings.textexpander (RUN AT YOUR OWN RISK!)')
|
50
78
|
on('-v', '--verbose', 'Turn on verbose output')
|
51
79
|
|
data/expandsync.gemspec
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# coding: utf-8
|
2
2
|
lib = File.expand_path('../lib', __FILE__)
|
3
3
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
-
require 'expandsync/
|
4
|
+
require 'expandsync/constants'
|
5
5
|
|
6
6
|
Gem::Specification.new do |spec|
|
7
7
|
spec.name = 'expandsync'
|
@@ -25,6 +25,7 @@ Gem::Specification.new do |spec|
|
|
25
25
|
|
26
26
|
spec.add_development_dependency('rake', '~> 0')
|
27
27
|
spec.add_development_dependency('aruba', '~> 0')
|
28
|
+
spec.add_dependency('cliutils', '~> 0')
|
28
29
|
spec.add_dependency('methadone', '~> 1.3', '>= 1.3.1')
|
29
30
|
spec.add_dependency('nokogiri', '~> 1.6', '>= 1.6.1')
|
30
31
|
end
|
@@ -7,9 +7,9 @@ Then(/^"(.*?)" should exist$/) do |file|
|
|
7
7
|
end
|
8
8
|
|
9
9
|
Then(/^Settings\.textexpander should be backed up$/) do
|
10
|
-
expect(
|
10
|
+
expect(Dir['/tmp/expandsync/Dropbox/TextExpander/*'].count).to eq(2)
|
11
11
|
end
|
12
12
|
|
13
13
|
Then(/^Settings\.textexpander should not be backed up$/) do
|
14
|
-
expect(
|
14
|
+
expect(Dir['/tmp/expandsync/Dropbox/TextExpander/*'].count).to eq(1)
|
15
15
|
end
|
data/lib/expandsync/atext.rb
CHANGED
@@ -1,69 +1,64 @@
|
|
1
|
-
|
2
|
-
# AText Class
|
3
|
-
# ======================================================
|
4
|
-
class AText
|
5
|
-
# ====================================================
|
6
|
-
# Constants
|
7
|
-
# ====================================================
|
8
|
-
OUTPUT_FILENAME = 'aText-snippets.csv'
|
9
|
-
OUTPUT_PATH = ENV['HOME']
|
1
|
+
require 'csv'
|
10
2
|
|
11
|
-
|
12
|
-
#
|
13
|
-
|
14
|
-
|
3
|
+
module ExpandSync
|
4
|
+
# AText Class
|
5
|
+
class AText
|
6
|
+
# The output filename
|
7
|
+
OUTPUT_FILENAME = 'aText-snippets.csv'
|
15
8
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
9
|
+
# The output filepath
|
10
|
+
OUTPUT_PATH = ENV['HOME']
|
11
|
+
|
12
|
+
# Stores the output filepath.
|
13
|
+
# @return [String]
|
14
|
+
attr_accessor :output_file
|
15
|
+
|
16
|
+
# Stores a CSV string of the snippets.
|
17
|
+
# @return [String]
|
18
|
+
attr_accessor :snippet_csv
|
19
|
+
|
20
|
+
# Stores an array of snippets.
|
21
|
+
# @return [Array]
|
22
|
+
attr_accessor :snippets
|
23
|
+
|
24
|
+
# Initialize by loading snippets from an aText CSV.
|
25
|
+
# @param [String] csv_filepath The filepath to the aText CSV
|
26
|
+
# @return [void]
|
27
|
+
def initialize(csv_filepath, custom_output_path)
|
28
|
+
if custom_output_path.nil?
|
29
|
+
@output_file = File.join(OUTPUT_PATH, OUTPUT_FILENAME)
|
31
30
|
else
|
32
|
-
|
31
|
+
if Dir.exists?(File.dirname(custom_output_path))
|
32
|
+
@output_file = custom_output_path
|
33
|
+
else
|
34
|
+
fail "Invalid output directory for aText: #{ custom_output_path }"
|
35
|
+
end
|
33
36
|
end
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
37
|
+
|
38
|
+
if File.exists?(csv_filepath) && File.extname(csv_filepath) == '.csv'
|
39
|
+
begin
|
40
|
+
@snippets = CSV.read(csv_filepath)
|
41
|
+
rescue
|
42
|
+
fail "Could not load CSV from file: #{ csv_filepath }"
|
43
|
+
end
|
44
|
+
|
45
|
+
@snippets.each { |s| s[2] = 'aText' }
|
46
|
+
else
|
47
|
+
fail "Invalid CSV file: #{ csv_filepath }"
|
41
48
|
end
|
42
|
-
|
43
|
-
@snippets.each { |s| s[2] = 'aText' }
|
44
|
-
else
|
45
|
-
fail "Invalid CSV file: #{ csv_filepath }"
|
46
49
|
end
|
47
|
-
end
|
48
|
-
|
49
|
-
# ----------------------------------------------------
|
50
|
-
# construct_data method
|
51
|
-
#
|
52
|
-
# Outputs a CSV listing of the supplied snippets
|
53
|
-
# @param new_snippets The snippet array to use
|
54
|
-
# @return String
|
55
|
-
# ----------------------------------------------------
|
56
|
-
def construct_data(new_snippets)
|
57
|
-
@snippet_csv = CSV.generate { |csv| new_snippets.each { |s| csv << [s[0], s[1]] } }
|
58
|
-
end
|
59
50
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
51
|
+
# Outputs a CSV listing of the supplied snippets
|
52
|
+
# @param [Array] new_snippets The snippet array to use
|
53
|
+
# @return [String]
|
54
|
+
def construct_data(new_snippets)
|
55
|
+
@snippet_csv = CSV.generate { |csv| new_snippets.each { |s| csv << [s[0], s[1]] } }
|
56
|
+
end
|
57
|
+
|
58
|
+
# Saves the current snippets to Settings.textexpander.
|
59
|
+
# @return [void]
|
60
|
+
def save
|
61
|
+
File.open(@output_file, 'w') {|f| f.write(@snippet_csv) }
|
62
|
+
end
|
68
63
|
end
|
69
64
|
end
|
@@ -1,5 +1,10 @@
|
|
1
1
|
module ExpandSync
|
2
|
+
# The Gem's description
|
2
3
|
DESCRIPTION = 'A command line app that synchronizes text expansion snippets between aText for OS X and TextExpander for iOS'
|
4
|
+
|
5
|
+
# The Gem's summary
|
3
6
|
SUMMARY = 'An engine for synchronizing snippets from aText on OS X and TextExpander Touch'
|
4
|
-
|
7
|
+
|
8
|
+
# The Gem's version
|
9
|
+
VERSION = '0.2.0'
|
5
10
|
end
|
@@ -1,179 +1,164 @@
|
|
1
|
+
require 'nokogiri'
|
1
2
|
require 'securerandom'
|
2
3
|
require 'time'
|
3
4
|
|
4
|
-
|
5
|
-
#
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
OUTPUT_PATH = File.join(ENV['HOME'], 'Dropbox', 'TextExpander')
|
5
|
+
module ExpandSync
|
6
|
+
# TextExpander Class
|
7
|
+
class TextExpander
|
8
|
+
# The output filename
|
9
|
+
OUTPUT_FILENAME = 'Settings.textexpander'
|
10
|
+
|
11
|
+
# The output filepath
|
12
|
+
OUTPUT_PATH = File.join(ENV['HOME'], 'Dropbox', 'TextExpander')
|
13
13
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
attr_accessor :base_xml, :output_file, :snippet_xml, :snippets
|
14
|
+
# Stores the initial XML as pulled from Settings.textexpander.
|
15
|
+
# @return [Nokogiri::XML::Document]
|
16
|
+
attr_accessor :base_xml
|
18
17
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
# ----------------------------------------------------
|
23
|
-
# initialize method
|
24
|
-
#
|
25
|
-
# @return Void
|
26
|
-
# ----------------------------------------------------
|
27
|
-
def initialize
|
28
|
-
begin
|
29
|
-
xpath = "/*/*/array[preceding-sibling::key[1] = 'snippetsTE2']/*"
|
30
|
-
@output_file = File.join(OUTPUT_PATH, OUTPUT_FILENAME)
|
31
|
-
@base_xml = Nokogiri::XML(File.open(@output_file))
|
32
|
-
@snippet_xml = @base_xml
|
18
|
+
# Stores the full output path for the produced XML.
|
19
|
+
# @return [String]
|
20
|
+
attr_accessor :output_file
|
33
21
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
22
|
+
# Stores the final XML to save.
|
23
|
+
# @return [Nokogiri::XML::Document]
|
24
|
+
attr_accessor :snippet_xml
|
25
|
+
|
26
|
+
# Stores an array of snippets.
|
27
|
+
# @return [Array]
|
28
|
+
attr_accessor :snippets
|
29
|
+
|
30
|
+
# Initialize by loading snippets from TextExpander.
|
31
|
+
# @return [void]
|
32
|
+
def initialize
|
33
|
+
begin
|
34
|
+
xpath = "/*/*/array[preceding-sibling::key[1] = 'snippetsTE2']/*"
|
35
|
+
@output_file = File.join(OUTPUT_PATH, OUTPUT_FILENAME)
|
36
|
+
@base_xml = Nokogiri::XML(File.open(@output_file))
|
37
|
+
@snippet_xml = @base_xml
|
38
|
+
|
39
|
+
arr = []
|
40
|
+
@base_xml.xpath(xpath).each do |snippet|
|
41
|
+
abbreviation = snippet.xpath("string[preceding-sibling::key[1] = 'abbreviation']").text
|
42
|
+
value = snippet.xpath("string[preceding-sibling::key[1] = 'plainText']").text
|
43
|
+
arr << [abbreviation, value, 'TextExpander']
|
44
|
+
end
|
45
|
+
@snippets = arr
|
46
|
+
rescue
|
47
|
+
fail "Invalid TextExpander XML file: #{ @output_file }"
|
39
48
|
end
|
40
|
-
@snippets = arr
|
41
|
-
rescue
|
42
|
-
fail "Invalid TextExpander XML file: #{ @output_file }"
|
43
49
|
end
|
44
|
-
end
|
45
50
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
# @param snippets An array of snippets to add
|
52
|
-
# @return Void
|
53
|
-
# ----------------------------------------------------
|
54
|
-
def add_group_to_base_xml(snippet_uuids)
|
55
|
-
groups_xpath = "/*/*/array[preceding-sibling::key[1] = 'groupsTE2']"
|
56
|
-
at_group_xpath = groups_xpath + "/*[string[preceding-sibling::key[1] = 'name'] = 'aText']"
|
57
|
-
|
58
|
-
if @snippet_xml.xpath(at_group_xpath).empty?
|
59
|
-
xml_builder = Nokogiri::XML::Builder.new do |xml|
|
60
|
-
xml.dict {
|
61
|
-
xml.key 'expandAfterMode'
|
62
|
-
xml.integer '0'
|
63
|
-
xml.key 'expanderExceptionsMode'
|
64
|
-
xml.integer '4'
|
65
|
-
xml.key 'name'
|
66
|
-
xml.string 'aText'
|
67
|
-
xml.key 'snippetUUIDs'
|
68
|
-
xml.array {
|
69
|
-
snippet_uuids.each do |u|
|
70
|
-
xml.string u
|
71
|
-
end
|
72
|
-
}
|
73
|
-
xml.key 'suggestAbbreviations'
|
74
|
-
xml.integer '1'
|
75
|
-
xml.key 'updateFrequency'
|
76
|
-
xml.integer '0'
|
77
|
-
xml.key 'uuidString'
|
78
|
-
xml.string SecureRandom.uuid.upcase
|
79
|
-
xml.key 'writable'
|
80
|
-
xml.integer '1'
|
81
|
-
}
|
82
|
-
end
|
83
|
-
@snippet_xml.xpath(groups_xpath)[0].add_child(xml_builder.doc.root.to_xml)
|
84
|
-
else
|
85
|
-
xml_builder = Nokogiri::XML::Builder.new do |xml|
|
86
|
-
xml.array {
|
87
|
-
snippet_uuids.each do |uuid|
|
88
|
-
xml.string uuid
|
89
|
-
end
|
90
|
-
}
|
91
|
-
end
|
92
|
-
|
93
|
-
@snippet_xml.xpath(at_group_xpath + "/array[preceding-sibling::key[1] = 'snippetUUIDs']")[0].add_child(xml_builder.doc.root.children.to_xml)
|
51
|
+
# Backs up the current TextExpander settings to a
|
52
|
+
# timestamped file in the same directory.
|
53
|
+
# @return [String]
|
54
|
+
def backup
|
55
|
+
FileUtils.cp(@output_file, @output_file + "_#{ Time.now.utc.iso8601 }")
|
94
56
|
end
|
95
|
-
end
|
96
57
|
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
def add_snippets_to_base_xml(snippets)
|
106
|
-
uuids = []
|
58
|
+
# Modifies the currently held XML data with new snippet
|
59
|
+
# information.
|
60
|
+
# @param [Array] new_snippets The snippet array to use
|
61
|
+
# @return [void]
|
62
|
+
def construct_data(new_snippets)
|
63
|
+
snippet_uuids = _add_snippets_to_base_xml(new_snippets)
|
64
|
+
_add_group_to_base_xml(snippet_uuids)
|
65
|
+
end
|
107
66
|
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
67
|
+
# Saves the current snippets to Settings.textexpander.
|
68
|
+
# @return [void]
|
69
|
+
def save
|
70
|
+
File.open(@output_file, 'w') {|f| f.write(@snippet_xml) }
|
71
|
+
end
|
72
|
+
|
73
|
+
private
|
74
|
+
|
75
|
+
# Creates correct group information for the provided
|
76
|
+
# snippets.
|
77
|
+
# @param [Array] snippets An array of snippet UUIDs
|
78
|
+
# @return [void]
|
79
|
+
def _add_group_to_base_xml(snippet_uuids)
|
80
|
+
groups_xpath = "/*/*/array[preceding-sibling::key[1] = 'groupsTE2']"
|
81
|
+
at_group_xpath = groups_xpath + "/*[string[preceding-sibling::key[1] = 'name'] = 'aText']"
|
82
|
+
|
83
|
+
if @snippet_xml.xpath(at_group_xpath).empty?
|
84
|
+
xml_builder = Nokogiri::XML::Builder.new do |xml|
|
114
85
|
xml.dict {
|
115
|
-
xml.key '
|
116
|
-
xml.string s[0]
|
117
|
-
xml.key 'abbreviationMode'
|
86
|
+
xml.key 'expandAfterMode'
|
118
87
|
xml.integer '0'
|
119
|
-
xml.key '
|
120
|
-
xml.
|
121
|
-
xml.key '
|
122
|
-
xml.
|
123
|
-
xml.key '
|
124
|
-
xml.
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
xml.key '
|
130
|
-
xml.integer '
|
131
|
-
xml.key '
|
88
|
+
xml.key 'expanderExceptionsMode'
|
89
|
+
xml.integer '4'
|
90
|
+
xml.key 'name'
|
91
|
+
xml.string 'aText'
|
92
|
+
xml.key 'snippetUUIDs'
|
93
|
+
xml.array {
|
94
|
+
snippet_uuids.each do |u|
|
95
|
+
xml.string u
|
96
|
+
end
|
97
|
+
}
|
98
|
+
xml.key 'suggestAbbreviations'
|
99
|
+
xml.integer '1'
|
100
|
+
xml.key 'updateFrequency'
|
132
101
|
xml.integer '0'
|
133
102
|
xml.key 'uuidString'
|
134
|
-
xml.string uuid
|
103
|
+
xml.string SecureRandom.uuid.upcase
|
104
|
+
xml.key 'writable'
|
105
|
+
xml.integer '1'
|
106
|
+
}
|
107
|
+
end
|
108
|
+
@snippet_xml.xpath(groups_xpath)[0].add_child(xml_builder.doc.root.to_xml)
|
109
|
+
else
|
110
|
+
xml_builder = Nokogiri::XML::Builder.new do |xml|
|
111
|
+
xml.array {
|
112
|
+
snippet_uuids.each do |uuid|
|
113
|
+
xml.string uuid
|
114
|
+
end
|
135
115
|
}
|
136
116
|
end
|
137
|
-
|
117
|
+
|
118
|
+
@snippet_xml.xpath(at_group_xpath + "/array[preceding-sibling::key[1] = 'snippetUUIDs']")[0].add_child(xml_builder.doc.root.children.to_xml)
|
119
|
+
end
|
138
120
|
end
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
# backup method
|
146
|
-
#
|
147
|
-
# Backs up the current TextExpander settings to a
|
148
|
-
# timestamped file in the same directory.
|
149
|
-
# @return String
|
150
|
-
# ----------------------------------------------------
|
151
|
-
def backup
|
152
|
-
FileUtils.cp(@output_file, @output_file + "_#{ Time.now.utc.iso8601 }")
|
153
|
-
end
|
154
|
-
|
155
|
-
# ----------------------------------------------------
|
156
|
-
# construct_data method
|
157
|
-
#
|
158
|
-
# Modifies the currently held XML data with new snippet
|
159
|
-
# information.
|
160
|
-
# @param new_snippets The snippet array to use
|
161
|
-
# @return Void
|
162
|
-
# ----------------------------------------------------
|
163
|
-
def construct_data(new_snippets)
|
164
|
-
snippet_uuids = add_snippets_to_base_xml(new_snippets)
|
165
|
-
add_group_to_base_xml(snippet_uuids)
|
166
|
-
end
|
121
|
+
|
122
|
+
# Inserts XML for the provided snippets to the base XML
|
123
|
+
# @param [Array] snippets An array of snippets to add and returns an array of snippet UUIDs
|
124
|
+
# @return [void]
|
125
|
+
def _add_snippets_to_base_xml(snippets)
|
126
|
+
uuids = []
|
167
127
|
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
128
|
+
xml_builder = Nokogiri::XML::Builder.new do |xml|
|
129
|
+
xml.snippets {
|
130
|
+
snippets.each do |s|
|
131
|
+
uuid = SecureRandom.uuid.upcase
|
132
|
+
uuids << uuid
|
133
|
+
|
134
|
+
xml.dict {
|
135
|
+
xml.key 'abbreviation'
|
136
|
+
xml.string s[0]
|
137
|
+
xml.key 'abbreviationMode'
|
138
|
+
xml.integer '0'
|
139
|
+
xml.key 'creationDate'
|
140
|
+
xml.date Time.now.utc.iso8601
|
141
|
+
xml.key 'flags'
|
142
|
+
xml.integer '0'
|
143
|
+
xml.key 'label'
|
144
|
+
xml.string
|
145
|
+
xml.key 'modificationDate'
|
146
|
+
xml.date Time.now.utc.iso8601
|
147
|
+
xml.key 'plainText'
|
148
|
+
xml.string s[1]
|
149
|
+
xml.key 'snippetType'
|
150
|
+
xml.integer '0'
|
151
|
+
xml.key 'useCount'
|
152
|
+
xml.integer '0'
|
153
|
+
xml.key 'uuidString'
|
154
|
+
xml.string uuid
|
155
|
+
}
|
156
|
+
end
|
157
|
+
}
|
158
|
+
end
|
159
|
+
|
160
|
+
@snippet_xml.xpath("/*/*/array[preceding-sibling::key[1] = 'snippetsTE2']")[0].add_child(xml_builder.doc.root.children.to_xml)
|
161
|
+
uuids
|
162
|
+
end
|
176
163
|
end
|
177
|
-
|
178
|
-
private :add_group_to_base_xml, :add_snippets_to_base_xml
|
179
164
|
end
|
data/lib/expandsync.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: expandsync
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Aaron Bach
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-04-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
@@ -38,6 +38,20 @@ dependencies:
|
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: cliutils
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
41
55
|
- !ruby/object:Gem::Dependency
|
42
56
|
name: methadone
|
43
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -107,9 +121,8 @@ files:
|
|
107
121
|
- features/support/env.rb
|
108
122
|
- lib/expandsync.rb
|
109
123
|
- lib/expandsync/atext.rb
|
110
|
-
- lib/expandsync/
|
124
|
+
- lib/expandsync/constants.rb
|
111
125
|
- lib/expandsync/textexpander.rb
|
112
|
-
- lib/expandsync/version.rb
|
113
126
|
- res/Settings.textexpander
|
114
127
|
- res/atext.csv
|
115
128
|
- res/expected-new-atext.csv
|
@@ -1,215 +0,0 @@
|
|
1
|
-
module ExpandSync
|
2
|
-
# ======================================================
|
3
|
-
# CliManager Module
|
4
|
-
# Singleton to manage common CLI interfacing
|
5
|
-
# ======================================================
|
6
|
-
module CLIMessage
|
7
|
-
# ====================================================
|
8
|
-
# Methods
|
9
|
-
# ====================================================
|
10
|
-
# ----------------------------------------------------
|
11
|
-
# error method
|
12
|
-
#
|
13
|
-
# Outputs a formatted-red error message.
|
14
|
-
# @param m The message to output
|
15
|
-
# @return Void
|
16
|
-
# ----------------------------------------------------
|
17
|
-
def self.error(m, log = true)
|
18
|
-
Methadone::CLILogging.error(m) if log
|
19
|
-
puts "---> ERROR: #{ m }".red
|
20
|
-
end
|
21
|
-
|
22
|
-
# ----------------------------------------------------
|
23
|
-
# info method
|
24
|
-
#
|
25
|
-
# Outputs a formatted-blue informational message.
|
26
|
-
# @param m The message to output
|
27
|
-
# @return Void
|
28
|
-
# ----------------------------------------------------
|
29
|
-
def self.info(m, log = true)
|
30
|
-
Methadone::CLILogging.info(m) if log
|
31
|
-
puts "---> INFO: #{ m }".blue
|
32
|
-
end
|
33
|
-
|
34
|
-
# ----------------------------------------------------
|
35
|
-
# info_block method
|
36
|
-
#
|
37
|
-
# Wraps a block in an opening and closing info message.
|
38
|
-
# @param m1 The opening message to output
|
39
|
-
# @param m2 The closing message to output
|
40
|
-
# @param multiline Whether the message should be multiline
|
41
|
-
# @return Void
|
42
|
-
# ----------------------------------------------------
|
43
|
-
def self.info_block(m1, m2 = 'Done.', multiline = false, log = true)
|
44
|
-
if block_given?
|
45
|
-
if multiline
|
46
|
-
info(m1, log)
|
47
|
-
else
|
48
|
-
print "---> INFO: #{ m1 }".blue
|
49
|
-
end
|
50
|
-
|
51
|
-
yield
|
52
|
-
|
53
|
-
if multiline
|
54
|
-
info(m2, log)
|
55
|
-
else
|
56
|
-
puts m2.blue
|
57
|
-
end
|
58
|
-
else
|
59
|
-
error = 'Did not specify a valid block'
|
60
|
-
Methadone::CLILogging.error(error) if log
|
61
|
-
fail ArgumentError, error
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
|
-
# ----------------------------------------------------
|
66
|
-
# prompt method
|
67
|
-
#
|
68
|
-
# Outputs a prompt, collects the user's response, and
|
69
|
-
# returns it.
|
70
|
-
# @param prompt The prompt to output
|
71
|
-
# @param default The default option
|
72
|
-
# @return String
|
73
|
-
# ----------------------------------------------------
|
74
|
-
def self.prompt(prompt, default = nil, log = true)
|
75
|
-
print "#{ prompt } #{ default.nil? ? '' : "[default: #{ default }]:" } ".blue
|
76
|
-
choice = $stdin.gets.chomp
|
77
|
-
if choice.empty?
|
78
|
-
r = default
|
79
|
-
else
|
80
|
-
r = choice
|
81
|
-
end
|
82
|
-
|
83
|
-
Methadone::CLILogging.info("Answer to '#{ prompt }': #{r}") if log
|
84
|
-
r
|
85
|
-
end
|
86
|
-
|
87
|
-
# ----------------------------------------------------
|
88
|
-
# section method
|
89
|
-
#
|
90
|
-
# Outputs a formatted-orange section message.
|
91
|
-
# @param m The message to output
|
92
|
-
# @return Void
|
93
|
-
# ----------------------------------------------------
|
94
|
-
def self.section(m, log = true)
|
95
|
-
Methadone::CLILogging.info(m) if log
|
96
|
-
puts "#### #{ m }".purple
|
97
|
-
end
|
98
|
-
|
99
|
-
# ----------------------------------------------------
|
100
|
-
# section_block method
|
101
|
-
#
|
102
|
-
# Wraps a block in an opening and closing section
|
103
|
-
# message.
|
104
|
-
# @param m1 The opening message to output
|
105
|
-
# @param m2 The closing message to output
|
106
|
-
# @param multiline A multiline message or not
|
107
|
-
# @return Void
|
108
|
-
# ----------------------------------------------------
|
109
|
-
def self.section_block(m, multiline = true, log = true)
|
110
|
-
if block_given?
|
111
|
-
if multiline
|
112
|
-
section(m, log)
|
113
|
-
else
|
114
|
-
print "#### #{ m }".purple
|
115
|
-
end
|
116
|
-
|
117
|
-
yield
|
118
|
-
else
|
119
|
-
error = 'Did not specify a valid block'
|
120
|
-
Methadone::CLILogging.error(error) if log
|
121
|
-
fail ArgumentError, error
|
122
|
-
end
|
123
|
-
end
|
124
|
-
|
125
|
-
# ----------------------------------------------------
|
126
|
-
# success method
|
127
|
-
#
|
128
|
-
# Outputs a formatted-green success message.
|
129
|
-
# @param m The message to output
|
130
|
-
# @return Void
|
131
|
-
# ----------------------------------------------------
|
132
|
-
def self.success(m, log = true)
|
133
|
-
Methadone::CLILogging.info(m) if log
|
134
|
-
puts "---> SUCCESS: #{ m }".green
|
135
|
-
end
|
136
|
-
|
137
|
-
# ----------------------------------------------------
|
138
|
-
# warning method
|
139
|
-
#
|
140
|
-
# Outputs a formatted-yellow warning message.
|
141
|
-
# @param m The message to output
|
142
|
-
# @return Void
|
143
|
-
# ----------------------------------------------------
|
144
|
-
def self.warning(m, log = true)
|
145
|
-
Methadone::CLILogging.warn(m) if log
|
146
|
-
puts "---> WARNING: #{ m }".yellow
|
147
|
-
end
|
148
|
-
end
|
149
|
-
end
|
150
|
-
|
151
|
-
# ======================================================
|
152
|
-
# String Class
|
153
|
-
# ======================================================
|
154
|
-
class String
|
155
|
-
# ----------------------------------------------------
|
156
|
-
# colorize method
|
157
|
-
#
|
158
|
-
# Outputs a string in a formatted color.
|
159
|
-
# @param color_code The code to use
|
160
|
-
# @return Void
|
161
|
-
# ----------------------------------------------------
|
162
|
-
def colorize(color_code)
|
163
|
-
"\e[#{ color_code }m#{ self }\e[0m"
|
164
|
-
end
|
165
|
-
|
166
|
-
# ----------------------------------------------------
|
167
|
-
# blue method
|
168
|
-
#
|
169
|
-
# Convenience method to output a blue string
|
170
|
-
# @return Void
|
171
|
-
# ----------------------------------------------------
|
172
|
-
def blue
|
173
|
-
colorize(34)
|
174
|
-
end
|
175
|
-
|
176
|
-
# ----------------------------------------------------
|
177
|
-
# green method
|
178
|
-
#
|
179
|
-
# Convenience method to output a green string
|
180
|
-
# @return Void
|
181
|
-
# ----------------------------------------------------
|
182
|
-
def green
|
183
|
-
colorize(32)
|
184
|
-
end
|
185
|
-
|
186
|
-
# ----------------------------------------------------
|
187
|
-
# purple method
|
188
|
-
#
|
189
|
-
# Convenience method to output a purple string
|
190
|
-
# @return Void
|
191
|
-
# ----------------------------------------------------
|
192
|
-
def purple
|
193
|
-
colorize(35)
|
194
|
-
end
|
195
|
-
|
196
|
-
# ----------------------------------------------------
|
197
|
-
# red method
|
198
|
-
#
|
199
|
-
# Convenience method to output a red string
|
200
|
-
# @return Void
|
201
|
-
# ----------------------------------------------------
|
202
|
-
def red
|
203
|
-
colorize(31)
|
204
|
-
end
|
205
|
-
|
206
|
-
# ----------------------------------------------------
|
207
|
-
# yellow method
|
208
|
-
#
|
209
|
-
# Convenience method to output a yellow string
|
210
|
-
# @return Void
|
211
|
-
# ----------------------------------------------------
|
212
|
-
def yellow
|
213
|
-
colorize(33)
|
214
|
-
end
|
215
|
-
end
|