dockedit 1.0.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.
@@ -0,0 +1,189 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DockEdit
4
+ # Factory for creating Dock tile elements.
5
+ #
6
+ # These helpers construct the REXML structures that represent apps,
7
+ # folders, and spacer tiles inside the Dock plist.
8
+ class TileFactory
9
+ # Create a spacer tile element.
10
+ #
11
+ # @param small [Boolean] When +true+, create a half-size spacer.
12
+ # @return [REXML::Element] Newly created tile `<dict>` element.
13
+ def self.create_spacer_tile(small: false)
14
+ tile_type = small ? 'small-spacer-tile' : 'spacer-tile'
15
+
16
+ spacer = REXML::Element.new('dict')
17
+
18
+ key1 = REXML::Element.new('key')
19
+ key1.text = 'tile-data'
20
+ spacer.add(key1)
21
+
22
+ tile_data = REXML::Element.new('dict')
23
+ label_key = REXML::Element.new('key')
24
+ label_key.text = 'file-label'
25
+ tile_data.add(label_key)
26
+ label_string = REXML::Element.new('string')
27
+ label_string.text = ''
28
+ tile_data.add(label_string)
29
+ spacer.add(tile_data)
30
+
31
+ key2 = REXML::Element.new('key')
32
+ key2.text = 'tile-type'
33
+ spacer.add(key2)
34
+
35
+ type_string = REXML::Element.new('string')
36
+ type_string.text = tile_type
37
+ spacer.add(type_string)
38
+
39
+ spacer
40
+ end
41
+
42
+ # Create an app tile element.
43
+ #
44
+ # @param app_path [String] Absolute path to the `.app` bundle.
45
+ # @param app_info [Hash] Parsed plist info from {PlistReader.read_app_info}.
46
+ # @return [REXML::Element] Newly created tile `<dict>` element.
47
+ def self.create_app_tile(app_path, app_info)
48
+ app_dict = REXML::Element.new('dict')
49
+
50
+ # tile-data key
51
+ td_key = REXML::Element.new('key')
52
+ td_key.text = 'tile-data'
53
+ app_dict.add(td_key)
54
+
55
+ # tile-data dict
56
+ tile_data = REXML::Element.new('dict')
57
+
58
+ # bundle-identifier
59
+ add_plist_key_value(tile_data, 'bundle-identifier', 'string', app_info['CFBundleIdentifier'])
60
+
61
+ # dock-extra
62
+ add_plist_key_value(tile_data, 'dock-extra', 'false', nil)
63
+
64
+ # file-data dict
65
+ fd_key = REXML::Element.new('key')
66
+ fd_key.text = 'file-data'
67
+ tile_data.add(fd_key)
68
+
69
+ file_data = REXML::Element.new('dict')
70
+ add_plist_key_value(file_data, '_CFURLString', 'string', "file://#{URI.encode_www_form_component(app_path).gsub('%2F', '/')}/")
71
+ add_plist_key_value(file_data, '_CFURLStringType', 'integer', '15')
72
+ tile_data.add(file_data)
73
+
74
+ # file-label
75
+ label = app_info['CFBundleName'] || app_info['CFBundleDisplayName'] || File.basename(app_path, '.app')
76
+ add_plist_key_value(tile_data, 'file-label', 'string', label)
77
+
78
+ # file-mod-date
79
+ add_plist_key_value(tile_data, 'file-mod-date', 'integer', '0')
80
+
81
+ # file-type
82
+ add_plist_key_value(tile_data, 'file-type', 'integer', '41')
83
+
84
+ # is-beta
85
+ add_plist_key_value(tile_data, 'is-beta', 'false', nil)
86
+
87
+ # parent-mod-date
88
+ add_plist_key_value(tile_data, 'parent-mod-date', 'integer', '0')
89
+
90
+ app_dict.add(tile_data)
91
+
92
+ # tile-type key
93
+ tt_key = REXML::Element.new('key')
94
+ tt_key.text = 'tile-type'
95
+ app_dict.add(tt_key)
96
+
97
+ tt_value = REXML::Element.new('string')
98
+ tt_value.text = 'file-tile'
99
+ app_dict.add(tt_value)
100
+
101
+ app_dict
102
+ end
103
+
104
+ # Create a folder tile element.
105
+ #
106
+ # @param folder_path [String] Absolute path to the folder.
107
+ # @param show_as [Integer] Show-as value (1=fan, 2=grid, 3=list, 4=auto).
108
+ # @param display_as [Integer] Display-as value (0=stack, 1=folder).
109
+ # @return [REXML::Element] Newly created folder tile `<dict>` element.
110
+ def self.create_folder_tile(folder_path, show_as: 4, display_as: 1)
111
+ folder_dict = REXML::Element.new('dict')
112
+
113
+ # tile-data key
114
+ td_key = REXML::Element.new('key')
115
+ td_key.text = 'tile-data'
116
+ folder_dict.add(td_key)
117
+
118
+ # tile-data dict
119
+ tile_data = REXML::Element.new('dict')
120
+
121
+ # arrangement (0 = by name)
122
+ add_plist_key_value(tile_data, 'arrangement', 'integer', '0')
123
+
124
+ # displayas (0 = stack, 1 = folder)
125
+ add_plist_key_value(tile_data, 'displayas', 'integer', display_as.to_s)
126
+
127
+ # file-data dict
128
+ fd_key = REXML::Element.new('key')
129
+ fd_key.text = 'file-data'
130
+ tile_data.add(fd_key)
131
+
132
+ file_data = REXML::Element.new('dict')
133
+ encoded_path = URI.encode_www_form_component(folder_path).gsub('%2F', '/')
134
+ add_plist_key_value(file_data, '_CFURLString', 'string', "file://#{encoded_path}/")
135
+ add_plist_key_value(file_data, '_CFURLStringType', 'integer', '15')
136
+ tile_data.add(file_data)
137
+
138
+ # file-label
139
+ label = File.basename(folder_path)
140
+ add_plist_key_value(tile_data, 'file-label', 'string', label)
141
+
142
+ # file-mod-date
143
+ add_plist_key_value(tile_data, 'file-mod-date', 'integer', '0')
144
+
145
+ # file-type
146
+ add_plist_key_value(tile_data, 'file-type', 'integer', '2')
147
+
148
+ # parent-mod-date
149
+ add_plist_key_value(tile_data, 'parent-mod-date', 'integer', '0')
150
+
151
+ # preferreditemsize (-1 = default)
152
+ add_plist_key_value(tile_data, 'preferreditemsize', 'integer', '-1')
153
+
154
+ # showas (1=fan, 2=grid, 3=list, 4=auto)
155
+ add_plist_key_value(tile_data, 'showas', 'integer', show_as.to_s)
156
+
157
+ folder_dict.add(tile_data)
158
+
159
+ # tile-type key
160
+ tt_key = REXML::Element.new('key')
161
+ tt_key.text = 'tile-type'
162
+ folder_dict.add(tt_key)
163
+
164
+ tt_value = REXML::Element.new('string')
165
+ tt_value.text = 'directory-tile'
166
+ folder_dict.add(tt_value)
167
+
168
+ folder_dict
169
+ end
170
+
171
+ # Helper to add a key/value pair to a plist `<dict>` element.
172
+ #
173
+ # @param dict [REXML::Element] Target `<dict>` element.
174
+ # @param key_name [String] Key to add.
175
+ # @param value_type [String] Name of the value element type (e.g. "string").
176
+ # @param value [String, nil] Optional text value for the element.
177
+ # @return [void]
178
+ def self.add_plist_key_value(dict, key_name, value_type, value)
179
+ key = REXML::Element.new('key')
180
+ key.text = key_name
181
+ dict.add(key)
182
+
183
+ val_elem = REXML::Element.new(value_type)
184
+ val_elem.text = value if value
185
+ dict.add(val_elem)
186
+ end
187
+ end
188
+ end
189
+
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DockEdit
4
+ # Current dockedit gem version.
5
+ VERSION = '1.0.0'
6
+ end
7
+
data/lib/dockedit.rb ADDED
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ # dockedit - A script to edit the macOS Dock
4
+ # Usage: dockedit <subcommand> [options] [args]
5
+
6
+ require 'rexml/document'
7
+ require 'fileutils'
8
+ require 'optparse'
9
+ require 'uri'
10
+ require 'stringio'
11
+
12
+ require_relative 'dockedit/version'
13
+ require_relative 'dockedit/constants'
14
+ require_relative 'dockedit/matcher'
15
+ require_relative 'dockedit/path_utils'
16
+ require_relative 'dockedit/plist_reader'
17
+ require_relative 'dockedit/plist_writer'
18
+ require_relative 'dockedit/app_finder'
19
+ require_relative 'dockedit/tile_factory'
20
+ require_relative 'dockedit/folder_updater'
21
+ require_relative 'dockedit/parsers'
22
+ require_relative 'dockedit/dock'
23
+ require_relative 'dockedit/commands'
24
+ require_relative 'dockedit/cli'
25
+
metadata ADDED
@@ -0,0 +1,82 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: dockedit
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Brett Terpstra
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: rexml
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - "~>"
17
+ - !ruby/object:Gem::Version
18
+ version: '3.2'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - "~>"
24
+ - !ruby/object:Gem::Version
25
+ version: '3.2'
26
+ description: dockedit allows you to add, remove, move, and manage apps and folders
27
+ in your macOS Dock from the command line
28
+ email:
29
+ - github@brettterpstra.com
30
+ executables:
31
+ - dockedit
32
+ extensions: []
33
+ extra_rdoc_files: []
34
+ files:
35
+ - ".rspec"
36
+ - CHANGELOG.md
37
+ - Gemfile
38
+ - Gemfile.lock
39
+ - README.md
40
+ - Rakefile
41
+ - bin/dockedit
42
+ - build_standalone.rb
43
+ - dockedit
44
+ - lib/dockedit.rb
45
+ - lib/dockedit/app_finder.rb
46
+ - lib/dockedit/cli.rb
47
+ - lib/dockedit/commands.rb
48
+ - lib/dockedit/constants.rb
49
+ - lib/dockedit/dock.rb
50
+ - lib/dockedit/folder_updater.rb
51
+ - lib/dockedit/matcher.rb
52
+ - lib/dockedit/parsers.rb
53
+ - lib/dockedit/path_utils.rb
54
+ - lib/dockedit/plist_reader.rb
55
+ - lib/dockedit/plist_writer.rb
56
+ - lib/dockedit/tile_factory.rb
57
+ - lib/dockedit/version.rb
58
+ homepage: https://github.com/ttscoff/dockedit
59
+ licenses:
60
+ - MIT
61
+ metadata:
62
+ homepage_uri: https://github.com/ttscoff/dockedit
63
+ source_code_uri: https://github.com/ttscoff/dockedit
64
+ changelog_uri: https://github.com/ttscoff/dockedit/blob/main/CHANGELOG.md
65
+ rdoc_options: []
66
+ require_paths:
67
+ - lib
68
+ required_ruby_version: !ruby/object:Gem::Requirement
69
+ requirements:
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ version: 2.7.0
73
+ required_rubygems_version: !ruby/object:Gem::Requirement
74
+ requirements:
75
+ - - ">="
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ requirements: []
79
+ rubygems_version: 3.6.7
80
+ specification_version: 4
81
+ summary: A command-line tool to edit the macOS Dock
82
+ test_files: []