expandsync 0.1.3 → 0.2.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.
- 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
|