tm_bundle_support 0.0.1

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 18b7a29af1e0c9e5131802a604c3d59e665effab
4
+ data.tar.gz: 61c2739bce6ad29a9d58ff1dbe131d6baa3be8a4
5
+ SHA512:
6
+ metadata.gz: 59788c4fd619fe1fb0579a6190b2d7dd0ce08ed343113e23c52fb5adf741c219454b61a4e60644c1e927839cbfe590632a7e9c3b75d0fcc7563ba799f2d2e3be
7
+ data.tar.gz: 8fca42f07ef672b1f062f974bdbf37efaeb093330d9fae339605fc4b2eed63c3bad3170db390dfaf5ab008255d3ecc8d031f7faa8344951ced349bd798d38476
data/bin/tm_bundle ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby -roptparse -rpathname -ryaml
2
+
3
+ lib = File.expand_path('../../lib', __FILE__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+
6
+ require "tm_bundle_support"
7
+ require "tm_bundle/command"
data/lib/tm_bundle.rb ADDED
@@ -0,0 +1,107 @@
1
+ require "active_support"
2
+ require "active_support/core_ext"
3
+ require "active_support/dependencies/autoload"
4
+ require "tm_bundle/plutil"
5
+
6
+ class TMBundle
7
+ extend ActiveSupport::Autoload
8
+
9
+ eager_autoload do
10
+ autoload :Menu, "tm_bundle/menu"
11
+ end
12
+
13
+ class Action
14
+ attr_accessor :path, :data
15
+ def initialize(path)
16
+ @path = path
17
+ @data = Plutil.load_json(path)
18
+ end
19
+
20
+ def inspect
21
+ "#{self.class.name}:> #{data['name']} > `#{path.basename}`"
22
+ end
23
+
24
+ def expected_path
25
+ @expected_path ||= data['name'].gsub(/[.:\/]+/, '.' => '_', ':' => '', '/' => '') + path.extname
26
+ end
27
+
28
+ def unmatching_path?
29
+ expected_path != path.basename.to_s
30
+ end
31
+
32
+ def method_missing(meth, *args, &blk)
33
+ meth_name = meth.to_s
34
+ if @data.key?(meth_name)
35
+ @data[meth_name]
36
+ else
37
+ super
38
+ end
39
+ end
40
+ end
41
+ class Command < Action; end
42
+ class Snippet < Action; end
43
+ class Macro < Action; end
44
+
45
+ attr_accessor :path, :actions, :data, :menu
46
+
47
+ def initialize(path = nil)
48
+ self.path = path ? Pathname.new(path) : Pathname.pwd
49
+ self.data = Plutil.load_json(@path/'info.plist')
50
+ self.menu = Menu.new(data['mainMenu'], @path)
51
+ self.actions = []
52
+ locate_actions
53
+ fill_missing_menu_names!
54
+ # menu.write_yaml_hierarchy!
55
+ end
56
+
57
+ def locate_actions
58
+ Pathname.glob("#{path}/{Commands,Snippets,Macros}/*.{plist,tm{Command,Snippet}}")
59
+ .group_by {|p| p.dirname.basename.to_s }
60
+ .each do |group, files|
61
+ # p group.downcase.to_sym, actions
62
+ files.each do |pathname|
63
+ actions << TMBundle.const_get(group.singularize.to_sym).new(pathname)
64
+ end
65
+ end
66
+ end
67
+
68
+ def fix_names!
69
+ actions.select(&:unmatching_path?).each do |action|
70
+ action.path.rename(action.path.dirname/action.expected_path)
71
+ end
72
+ end
73
+
74
+ def fill_missing_menu_names!
75
+ actions.each do |action|
76
+ if item = menu.uuids[action.uuid]
77
+ item.name ||= action.name
78
+ else
79
+ Menu.find_or_create_new_item(action.uuid, 0, name: action.name)
80
+ end
81
+ end
82
+ end
83
+
84
+ def menu_export!(prefix)
85
+ fill_missing_menu_names!
86
+ menu.write_yaml_hierarchy!(prefix && "-#{prefix}")
87
+ end
88
+
89
+ def save_plist!(type = :default)
90
+ fill_missing_menu_names!
91
+
92
+ file = case type
93
+ when :last then Pathname.glob((path/"menu-*.yml").to_s).last
94
+ when String then path/"menu-#{type}.yml"
95
+ else path/"menu.yml" end
96
+
97
+ hash = menu.read_yaml_hieararchy! file
98
+ xml = process_xml_output Plutil::JSON.dump(hash)
99
+ puts Plutil.replace(@path/'info.plist', 'mainMenu', xml, &:read)
100
+ end
101
+
102
+ def process_xml_output(xml)
103
+ xml.lines[3...-1]
104
+ .join
105
+ .gsub(/(?<=$\n|\t)\t/, "\n\t" => "\n", "\t" => " ")
106
+ end
107
+ end
@@ -0,0 +1,36 @@
1
+ # params[:a] = true # -a
2
+ # params[:b] = "1" # -b1
3
+ # params[:foo] = "1" # --foo
4
+ # params[:bar] = "x" # --bar x
5
+ # params[:zot] = "z" # --zot Z
6
+
7
+ def start
8
+ TMBundle.eager_load!
9
+ @tmb = TMBundle.new
10
+ yield
11
+ end
12
+
13
+ case ARGV.shift
14
+ when "fix-names"
15
+ start {@tmb.fix_names!}
16
+ when "menu"
17
+ case ARGV.shift
18
+ when "export"
19
+ params = ARGV.getopts("fp:")
20
+ prefix = params['p'] || Time.now.to_formatted_s(:number) unless params['f']
21
+ start{
22
+ p params
23
+ @tmb.menu_export!(prefix)
24
+ }
25
+ when "apply"
26
+ start {
27
+ params = ARGV.getopts("v:", "last")
28
+ type = params['last'] || params['v']
29
+ @tmb.save_plist! type
30
+ }
31
+ else
32
+ puts " (export,apply)"
33
+ end
34
+ else
35
+ puts " (fix-names,menu)"
36
+ end
@@ -0,0 +1,68 @@
1
+ class TMBundle
2
+ class Menu
3
+ class Item
4
+ attr_accessor :uuid, :name, :items, :exclude, :parent, :order
5
+ def initialize(uuid, order, name: nil, items: [], parent: nil)
6
+ @exclude = false
7
+ self.uuid = uuid
8
+ self.name = name
9
+ self.items = items
10
+ self.parent = parent
11
+ self.order = order
12
+ end
13
+
14
+ def checkout(options = {})
15
+ self.name ||= options[:name]
16
+ self.parent ||= options[:parent]
17
+ self.order ||= options[:order]
18
+ self.items = Array.wrap(options[:items])
19
+ self
20
+ end
21
+
22
+ def items=(uuids)
23
+ @items = process_items(uuids)
24
+ end
25
+
26
+ def process_items(uuids)
27
+ uuids.map.with_index{|id, index| Menu.find_or_create_new_item(id, index, parent: uuid) }
28
+ end
29
+
30
+ def eql?(other)
31
+ uuid == other.uuid
32
+ end
33
+
34
+ def inspect
35
+ "#{order||:nil}> * #{name || uuid}"
36
+ end
37
+
38
+ def name?
39
+ name.present?
40
+ end
41
+
42
+ def items; @items ||= []; end
43
+ def to_s; name; end
44
+ def root?; !@parent; end
45
+ def separator?; false; end
46
+ end
47
+
48
+ class Separator < Item
49
+ def inspect
50
+ "#{order}> — #{name}"
51
+ end
52
+
53
+ def initialize(uuid, order, options = {})
54
+ @exclude = false
55
+ self.uuid = uuid
56
+ self.name = uuid
57
+ self.order = order
58
+ self.parent = options[:parent]
59
+ end
60
+
61
+ def eql?
62
+ order == order && parent == parent
63
+ end
64
+
65
+ def separator?; true end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,90 @@
1
+ class TMBundle
2
+ class Menu
3
+ extend ActiveSupport::Autoload
4
+
5
+ eager_autoload do
6
+ autoload :Item, "tm_bundle/item"
7
+ autoload :Separator, "tm_bundle/item"
8
+ end
9
+
10
+ cattr_accessor(:uuids){ Hash[] }
11
+ cattr_accessor(:items){ Set.new }
12
+
13
+ def self.find_or_create_new_item(uuid, order, attributes = {})
14
+ item = if uuid.squeeze == '-'
15
+ Separator.new(uuid, order, attributes)
16
+ elsif exists?(uuid)
17
+ uuids[uuid].checkout(attributes.to_h)
18
+ else
19
+ Item.new(uuid, order, attributes.to_h)
20
+ end
21
+
22
+ items.add item if item.is_a?(Item) && item.root?
23
+ unless item.is_a? Separator
24
+ uuids[uuid] ||= item
25
+ end
26
+ item
27
+ end
28
+
29
+ def self.exists?(uuid)
30
+ uuids.key? uuid
31
+ end
32
+
33
+ def initialize(tree, path)
34
+ @path = path
35
+ submenus, items, @excludedItems = *tree.values_at("submenus", "items", "excludedItems")
36
+ process_subtree(submenus)
37
+ end
38
+
39
+ def process_subtree(submenus)
40
+ submenus.each do |uuid, hash|
41
+ self.class.find_or_create_new_item(uuid, submenus.keys.index(uuid), hash.symbolize_keys)
42
+ end
43
+ end
44
+
45
+ def write_yaml_hierarchy!(prefix = nil)
46
+ p prefix
47
+ tree = make_hash_tree! uuids.values.select(&:root?)
48
+ yaml = tree.to_yaml.gsub(/^(.*)\s*$\n\s*:uuid:(.*)$/){|s,n| "%-60s # %s" % [$1, $2] }
49
+ (Pathname.new(@path)/"menu#{prefix}.yml").write(yaml)
50
+ end
51
+
52
+ def read_yaml_hieararchy!(file)
53
+ yaml = file.read
54
+ yaml.gsub!(/^(\s*)(.*)\s*#\s*(.*)$/){|s,n| "#{$1}%s \n#{$1} :uuid: %s" % [$2, $3] }
55
+ prepare_items_to_plist YAML.load(yaml)
56
+ end
57
+
58
+ def make_hash_tree!(items)
59
+ items.reduce(Hash[]) do |m, item|
60
+ hash = { uuid: item.uuid }
61
+ hash[:items] = make_hash_tree!(item.items) if item.items.any?
62
+
63
+ m.merge! item.name => hash
64
+ end
65
+ end
66
+
67
+ def prepare_items_to_plist(hash)
68
+ @menu = { submenus: {}, items: [], excludedItems: Array.wrap(@excludedItems) }
69
+ @menu[:items] = Array.wrap(iterate_to_plist(hash))
70
+ @menu
71
+ end
72
+
73
+ def iterate_to_plist(hash, parent = nil)
74
+ ary = []
75
+ hash.each do |name, tree|
76
+ uuid = tree[:uuid]
77
+ if tree[:items]
78
+ ary << uuid
79
+ @menu[:submenus][uuid] = {
80
+ :items => iterate_to_plist(tree[:items]),
81
+ :name => name
82
+ }
83
+ else
84
+ ary << uuid
85
+ end
86
+ end
87
+ ary
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,112 @@
1
+ require 'json'
2
+
3
+ class Plutil
4
+ module JSON
5
+ def self.load(plist)
6
+ Plutil.convert plist, to: :json do |converted_io|
7
+ ::JSON.load(converted_io)
8
+ end
9
+ end
10
+
11
+ def self.call(*args)
12
+ load(*args)
13
+ end
14
+
15
+ def self.dump(object, options = {})
16
+ Plutil.convert :stdin, options.reverse_merge(to: :xml) do |io|
17
+ io.write ::JSON.dump(object.to_h)
18
+ io.close_write
19
+ io.read
20
+ end
21
+ end
22
+ end
23
+
24
+ # Also aliased as `Plutil.plutil`
25
+ # Usage:
26
+ #
27
+ # Plutil.(:remove, "keypath", file: plist, &:read)
28
+ # Plutil.(:extract, "keypath", :json, file: plist, &:read)
29
+ #
30
+ def self.call(*args, &block)
31
+ new(*args).execute(&block)
32
+ end
33
+
34
+ # Usage:
35
+ #
36
+ # Plutil.insert('keypath', "-bool", "YES", file: plist, &:read)
37
+ #
38
+ class << self
39
+ alias_method :plutil, :call
40
+
41
+ [:remove, :extract, :insert].each do |command|
42
+ define_method(command) {|*args, &block| plutil(command, *args, &block) }
43
+ end
44
+ end
45
+
46
+ # Usage:
47
+ #
48
+ # Plutil.convert plist, to: 'json' do |converted_io|
49
+ # JSON.load(converted_io)
50
+ # end
51
+ #
52
+ def self.convert(path, to: :json, &block)
53
+ to = "xml1" if to.to_s == 'xml'
54
+ plutil(:convert, to, out: :stdin, file: path.to_s, &block)
55
+ end
56
+
57
+ # Usage:
58
+ #
59
+ # Plutil.replace(plist, 'name', data, as: 'xml', &:read)
60
+ #
61
+ def self.replace(path, keypath, data, as: :xml, &block)
62
+ plutil(:replace, keypath, "-#{as}", data, file: path.to_s, &block)
63
+ end
64
+
65
+ # Shorthand to `Plutil::JSON.load(plist)`
66
+ def self.load_json(*args)
67
+ Plutil::JSON.load(*args)
68
+ end
69
+
70
+ def self.dump_json(*args)
71
+ Plutil::JSON.dump(*args)
72
+ end
73
+
74
+ def initialize(*args)
75
+ options = args.extract_options!
76
+ @command, *@args = *args
77
+ @in, @out, @mode = *options.values_at(:in, :out, :mode)
78
+ @in ||= options[:file]
79
+ @mode ||= auto_mode
80
+ end
81
+
82
+ def execute(&block)
83
+ io = IO.popen(cmd, @mode)
84
+ block.call(io)
85
+ ensure
86
+ io.close if io && !io.closed?
87
+ end
88
+
89
+ def output_args; @out && ['-o', normalize_io_arg(@out)]; end
90
+ def input_args; @in && ['--', normalize_io_arg(@in)]; end
91
+ def stdin?; @in.to_s == 'stdin'; end
92
+
93
+ private
94
+ def cmd
95
+ ['plutil', "-#@command"] + Array(@args.map(&:to_s)) + Array(output_args) + Array(input_args)
96
+ end
97
+
98
+ def normalize_io_arg(io)
99
+ case io.to_s
100
+ when 'stdin', 'stdout' then '-'
101
+ else io
102
+ end
103
+ end
104
+
105
+ def auto_mode
106
+ case @command
107
+ when :convert then stdin? ? 'w+' : 'r'
108
+ when :replace then 'w+'
109
+ else 'r'
110
+ end
111
+ end
112
+ end
@@ -0,0 +1 @@
1
+ require "tm_bundle"
metadata ADDED
@@ -0,0 +1,101 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: tm_bundle_support
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Tōnis Simo
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-01-29 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activesupport
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '4.1'
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: '4.2'
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - "~>"
28
+ - !ruby/object:Gem::Version
29
+ version: '4.1'
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: '4.2'
33
+ - !ruby/object:Gem::Dependency
34
+ name: bundler
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '1.7'
40
+ type: :development
41
+ prerelease: false
42
+ version_requirements: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '1.7'
47
+ - !ruby/object:Gem::Dependency
48
+ name: rake
49
+ requirement: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: '10.0'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: '10.0'
61
+ description: Helpful ruby scripts for textmate bundle developers.
62
+ email:
63
+ - anton.estum@gmail.com
64
+ executables:
65
+ - tm_bundle
66
+ extensions: []
67
+ extra_rdoc_files: []
68
+ files:
69
+ - bin/tm_bundle
70
+ - lib/tm_bundle.rb
71
+ - lib/tm_bundle/command.rb
72
+ - lib/tm_bundle/item.rb
73
+ - lib/tm_bundle/menu.rb
74
+ - lib/tm_bundle/plutil.rb
75
+ - lib/tm_bundle_support.rb
76
+ homepage: http://github.com/estum/tm_bundle_support
77
+ licenses:
78
+ - MIT
79
+ metadata: {}
80
+ post_install_message:
81
+ rdoc_options: []
82
+ require_paths:
83
+ - lib
84
+ required_ruby_version: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ version: '2.1'
89
+ required_rubygems_version: !ruby/object:Gem::Requirement
90
+ requirements:
91
+ - - ">="
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ requirements: []
95
+ rubyforge_project:
96
+ rubygems_version: 2.4.5
97
+ signing_key:
98
+ specification_version: 4
99
+ summary: Textmate Bundle Support Tools
100
+ test_files: []
101
+ has_rdoc: