alphred 1.2.2 → 2.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 10082ff7a1c31db5ad28cab456c3e7137548cf11
4
- data.tar.gz: ee77fca7bd2179bfa450d5008076939d6bbbd5d2
3
+ metadata.gz: 6e16e15e9c29efb59e1db59f3c521e7434a72792
4
+ data.tar.gz: e9e42358283d6f3b43f89c7a5e93e658de747bdf
5
5
  SHA512:
6
- metadata.gz: 25214cc2776cb407ca5a8d531045f66fbdbb7153e0a77240ab1fedc17432c4e92779498c744b0bc666dd3adad8761576fdfa87de8c95fa8bbf16926ebad97a8a
7
- data.tar.gz: 88bad2ca507218e07f7c4ef74cd2386b399ac49730373645ed38a8d5c6ecd38283164d5ea435659acd7b229d99d42c2d29f694aa288db77e591dd19af44790de
6
+ metadata.gz: 5fc789dedf8233a24917d2084f4c8340525b97df36932036acccd1a9223299dd0fad05ec258c85cd5ecaa394c75c6ed5746b6df2ce9728d15eef64f0c0df64a0
7
+ data.tar.gz: b9bac5f7129ebf6f67488c318c5b8a200ed0cb2a819ffd87afa71786440482fac4b0a157f7a3040becfdf69365f0e1ff8e5b578a7af2232fbdde1d56de261300
data/Gemfile CHANGED
@@ -1,12 +1,12 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
- ruby "2.0.0"
3
+ ruby '2.0.0'
4
4
 
5
5
  # Specify your gem's dependencies in alphred.gemspec
6
6
  gemspec
7
7
 
8
8
  group :development do
9
- gem "guard"
10
- gem "guard-minitest"
11
- gem "pry"
9
+ gem 'guard'
10
+ gem 'guard-minitest'
11
+ gem 'pry'
12
12
  end
data/README.md CHANGED
@@ -86,34 +86,6 @@ This produces the following XML:
86
86
  </items>
87
87
  ```
88
88
 
89
- ### Workflow Configuration
90
-
91
- `Alphred::Config` provides some helpers for managing configuration that should
92
- persist when updating the workflow. This configuration is stored in an JSON
93
- file in the workflow data directory.
94
-
95
- ``` ruby
96
- # config.rb
97
-
98
- module Workflow
99
- defaults = { foo: "bar" }
100
- Config = Alphred::Config.new(**defaults)
101
- ```
102
-
103
- The corresponding Script Filter input and Run Action output then look like this:
104
-
105
- ``` shell
106
- # script filter
107
-
108
- ruby -r./config -e'puts Workflow::Config.filter_xml("{query}")'
109
- ```
110
-
111
- ``` shell
112
- # run action
113
-
114
- ruby -r./config -e'Forecast::Config.update!("{query}")'
115
- ```
116
-
117
89
  ### Releasing
118
90
 
119
91
  Including `alphred/tasks` in your `Rakefile` will allow access to Alphred's
@@ -1,26 +1,27 @@
1
1
  # coding: utf-8
2
- lib = File.expand_path("../lib", __FILE__)
2
+ lib = File.expand_path('../lib', __FILE__)
3
3
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
- require "alphred/version"
4
+ require 'alphred/version'
5
5
 
6
6
  Gem::Specification.new do |spec|
7
- spec.name = "alphred"
7
+ spec.name = 'alphred'
8
8
  spec.version = Alphred::VERSION
9
- spec.authors = ["Alpha Chen"]
10
- spec.email = ["alpha.chen@gmail.com"]
9
+ spec.authors = ['Alpha Chen']
10
+ spec.email = ['alpha.chen@gmail.com']
11
11
 
12
12
  spec.summary = %q{Helper utilities for making Alfred workflows.}
13
- spec.homepage = "https://github.com/kejadlen/alph"
14
- spec.license = "MIT"
13
+ spec.homepage = 'https://github.com/kejadlen/alphred'
14
+ spec.license = 'MIT'
15
15
 
16
16
  spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
17
- spec.bindir = "bin"
17
+ spec.bindir = 'bin'
18
18
  spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
19
- spec.require_paths = ["lib"]
19
+ spec.require_paths = ['lib']
20
20
 
21
- spec.add_dependency "builder", "~> 3.2"
21
+ spec.add_dependency 'builder', '~> 3.2'
22
22
 
23
- spec.add_development_dependency "bundler", "~> 1.10"
24
- spec.add_development_dependency "rake", "~> 10.0"
25
- spec.add_development_dependency "minitest"
23
+ spec.add_development_dependency 'bundler', '~> 1.10'
24
+ spec.add_development_dependency 'rake', '~> 10.0'
25
+ spec.add_development_dependency 'listen', '~> 3.0.0'
26
+ spec.add_development_dependency 'minitest'
26
27
  end
@@ -1,11 +1,5 @@
1
- require "builder"
1
+ require_relative 'alphred/version'
2
2
 
3
- require_relative "alphred/version"
4
-
5
- require_relative "alphred/config"
6
- require_relative "alphred/error"
7
- require_relative "alphred/icon"
8
- require_relative "alphred/item"
9
- require_relative "alphred/items"
10
- require_relative "alphred/mods"
11
- require_relative "alphred/text"
3
+ require_relative 'alphred/error'
4
+ require_relative 'alphred/item'
5
+ require_relative 'alphred/items'
@@ -1,14 +1,16 @@
1
- require_relative "item"
2
- require_relative "items"
1
+ require_relative 'item'
2
+ require_relative 'items'
3
+
4
+ require 'json'
3
5
 
4
6
  module Alphred
5
7
  class Error < StandardError
6
- ASSETS = File.expand_path("../../../assets", __FILE__)
8
+ ASSETS = File.expand_path('../../../assets', __FILE__)
7
9
 
8
10
  def self.try
9
11
  yield
10
12
  rescue Exception => e
11
- puts self.new(e).to_xml
13
+ print self.new(e).to_json
12
14
  end
13
15
 
14
16
  attr_reader :error
@@ -17,30 +19,32 @@ module Alphred
17
19
  @error = error
18
20
  end
19
21
 
22
+ def to_json(options=nil)
23
+ to_items.to_json(options)
24
+ end
25
+
20
26
  def to_items
21
- icon = File.join(ASSETS, "close.png")
27
+ icon = File.join(ASSETS, 'close.png')
22
28
  items = [ Alphred::Item.new(title: "#{self.error.class}: #{self.error}",
23
29
  icon: icon) ]
24
30
  items.concat(self.backtrace_items)
25
- Alphred::Items.new(*items)
26
- end
27
-
28
- def to_xml
29
- self.to_items.to_xml
31
+ Items[*items]
30
32
  end
31
33
 
32
34
  def backtrace_items
33
- icon = File.join(ASSETS, "more.png")
35
+ icon = File.join(ASSETS, 'more.png')
34
36
 
35
- base_dirs = $LOAD_PATH + [ENV["alfred_preferences"]]
37
+ base_dirs = $LOAD_PATH + [ENV['alfred_preferences']]
36
38
  to_delete = /^#{base_dirs.join(?|)}/
37
39
 
38
- self.error.backtrace.map {|line|
39
- title = line.sub(to_delete, "...")
40
- Alphred::Item.new(title: title,
41
- subtitle: line,
42
- arg: line,
43
- icon: icon)
40
+ self.error.backtrace.map { |line|
41
+ title = line.sub(to_delete, '...')
42
+ Item.new(
43
+ title: title,
44
+ subtitle: line,
45
+ arg: line,
46
+ icon: icon,
47
+ )
44
48
  }
45
49
  end
46
50
  end
@@ -1,59 +1,53 @@
1
- require "builder"
2
-
3
- require_relative "mods"
4
- require_relative "text"
1
+ require_relative 'struct'
5
2
 
6
3
  module Alphred
7
- class Item
8
- VALID_TYPES = %i[ default file file_skipcheck ]
9
-
10
- attr_accessor *%i[ uid arg valid autocomplete title subtitle mods icon text ]
11
-
12
- def initialize(**kwargs)
13
- raise ArgumentError.new("missing keyword: title") unless kwargs.has_key?(:title)
14
-
15
- @title = kwargs[:title]
16
-
17
- %i[ uid arg valid autocomplete subtitle ].each do |attr|
18
- self.instance_variable_set("@#{attr}", kwargs[attr]) if kwargs.has_key?(attr)
19
- end
20
-
21
- @icon = Icon(kwargs[:icon]) if kwargs.has_key?(:icon)
22
- @text = Text.new(kwargs[:text]) if kwargs.has_key?(:text)
23
- @mods = Mods.new(kwargs[:mods]) if kwargs.has_key?(:mods)
24
-
25
- self.type = kwargs[:type] if kwargs.has_key?(:type)
26
- end
4
+ class Item < Struct
5
+ attribute :valid, coerce: ->(x) { !!x }
6
+ attribute :uid
7
+ attribute :type,
8
+ coerce: ->(x) { x.to_s.gsub(?_, ?:) },
9
+ enum: %w[ default file file:skipcheck ]
10
+ attribute :title, required: true
11
+ attribute :subtitle
12
+ attribute :arg
13
+ attribute :autocomplete
14
+ attribute :icon, coerce: ->(x) { Icon(x) }
15
+ attribute :quicklookurl
16
+ attribute :mods, coerce: ->(x) { Mods.new(x) }
17
+ attribute :text, coerce: ->(x) { Text.new(x) }
18
+ end
27
19
 
28
- def type=(type)
29
- raise ArgumentError.new("`type` must be one of #{VALID_TYPES}") unless type.nil? || VALID_TYPES.include?(type)
20
+ class Icon < Struct
21
+ attribute :type, enum: %i[ fileicon filetype ]
22
+ attribute :path, required: true
23
+ end
30
24
 
31
- @type = type
32
- end
25
+ class Mod < Struct
26
+ attribute :valid, coerce: ->(x) { !!x }
27
+ attribute :arg
28
+ attribute :subtitle
29
+ end
33
30
 
34
- def type
35
- @type && @type.to_s.gsub(?_, ?:)
36
- end
31
+ class Mods < Struct
32
+ attribute :ctrl, coerce: ->(x) { Mod.new(x) }
33
+ attribute :alt, coerce: ->(x) { Mod.new(x) }
34
+ attribute :cmd, coerce: ->(x) { Mod.new(x) }
35
+ attribute :fn, coerce: ->(x) { Mod.new(x) }
36
+ attribute :shift, coerce: ->(x) { Mod.new(x) }
37
+ end
37
38
 
38
- def to_xml(xml=nil)
39
- xml ||= Builder::XmlMarkup.new(indent: 2)
40
- xml.item self.attrs do
41
- xml.title self.title
42
- xml.subtitle self.subtitle unless self.subtitle.nil?
43
- self.icon.to_xml(xml) unless self.icon.nil?
44
- self.mods.to_xml(xml) unless self.mods.nil?
45
- self.text.to_xml(xml) unless self.text.nil?
46
- end
47
- end
39
+ class Text < Struct
40
+ attribute :copy
41
+ attribute :largetype
42
+ end
43
+ end
48
44
 
49
- def attrs
50
- attrs = {}
51
- %i[ uid arg autocomplete type ].each do |attr|
52
- value = self.send(attr)
53
- attrs[attr] = value unless value.nil?
54
- end
55
- attrs[:valid] = (self.valid) ? "yes" : "no" unless self.valid.nil?
56
- attrs
45
+ module Kernel
46
+ def Icon(arg)
47
+ case arg
48
+ when Alphred::Icon then arg
49
+ when String then Alphred::Icon.new(path: arg)
50
+ when Hash then Alphred::Icon.new(**arg)
57
51
  end
58
52
  end
59
53
  end
@@ -1,8 +1,13 @@
1
- require "builder"
2
- require "delegate"
1
+ require 'delegate'
2
+
3
+ require 'json'
3
4
 
4
5
  module Alphred
5
6
  class Items < DelegateClass(Array)
7
+ def self.[](*args)
8
+ new(*args)
9
+ end
10
+
6
11
  attr_reader :items
7
12
 
8
13
  def initialize(*items)
@@ -10,14 +15,8 @@ module Alphred
10
15
  super(@items)
11
16
  end
12
17
 
13
- def to_xml
14
- xml = Builder::XmlMarkup.new(indent: 2)
15
- xml.instruct! :xml
16
- xml.items do
17
- self.items.each do |item|
18
- item.to_xml(xml)
19
- end
20
- end
18
+ def to_json(options=nil)
19
+ { items: items }.to_json(options)
21
20
  end
22
21
  end
23
22
  end
@@ -0,0 +1,71 @@
1
+ require 'json'
2
+
3
+ module Alphred
4
+ class Struct
5
+ class RequiredAttributeError < StandardError; end
6
+ class InvalidEnumError < StandardError; end
7
+ class InvalidAttributeError < StandardError; end
8
+
9
+ def self.attribute(name, **options)
10
+ attributes << Attribute.new(name, **options)
11
+
12
+ define_method(name) do
13
+ attributes[name]
14
+ end
15
+ end
16
+
17
+ def self.attributes
18
+ return @attributes if defined?(@attributes)
19
+ @attributes = []
20
+ end
21
+
22
+ attr_reader :attributes
23
+
24
+ def initialize(**input)
25
+ validate_input(input)
26
+
27
+ @attributes = self.class.attributes.select { |attr|
28
+ attr.required? || input.keys.include?(attr.name)
29
+ }.reduce({}) { |hash, attr|
30
+ hash.merge(attr.value_from(input))
31
+ }
32
+ end
33
+
34
+ def to_json(options=nil)
35
+ attributes.to_json(options)
36
+ end
37
+
38
+ private
39
+
40
+ def validate_input(input)
41
+ attribute_names = self.class.attributes.map(&:name)
42
+ invalid_keys = input.keys.reject {|key| attribute_names.include?(key) }
43
+ unless invalid_keys.empty?
44
+ msg = "Invalid attribute(s): #{invalid_keys.join(', ')}"
45
+ raise InvalidAttributeError.new(msg)
46
+ end
47
+ end
48
+
49
+ class Attribute
50
+ attr_reader :name, :coerce, :enum
51
+
52
+ def initialize(name, **options)
53
+ @name = name
54
+ @required = options.fetch(:required, false)
55
+ @coerce = options.fetch(:coerce, ->(x) { x })
56
+ @enum = options[:enum]
57
+ end
58
+
59
+ def required?
60
+ !!@required
61
+ end
62
+
63
+ def value_from(hash)
64
+ uncoerced = hash.fetch(name) { raise RequiredAttributeError.new(name) }
65
+ coerced = coerce.call(uncoerced)
66
+ raise InvalidEnumError.new(coerced) if enum && !enum.include?(coerced)
67
+ { name => coerced }
68
+ end
69
+ end
70
+ end
71
+ end
@@ -1,3 +1,3 @@
1
1
  module Alphred
2
- VERSION = '1.2.2'
2
+ VERSION = '2.0.0'
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: alphred
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.2
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alpha Chen
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-04-18 00:00:00.000000000 Z
11
+ date: 2016-07-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: builder
@@ -52,6 +52,20 @@ dependencies:
52
52
  - - ~>
53
53
  - !ruby/object:Gem::Version
54
54
  version: '10.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: listen
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: 3.0.0
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ~>
67
+ - !ruby/object:Gem::Version
68
+ version: 3.0.0
55
69
  - !ruby/object:Gem::Dependency
56
70
  name: minitest
57
71
  requirement: !ruby/object:Gem::Requirement
@@ -87,16 +101,13 @@ files:
87
101
  - assets/close.png
88
102
  - assets/more.png
89
103
  - lib/alphred.rb
90
- - lib/alphred/config.rb
91
104
  - lib/alphred/error.rb
92
- - lib/alphred/icon.rb
93
105
  - lib/alphred/item.rb
94
106
  - lib/alphred/items.rb
95
- - lib/alphred/mods.rb
107
+ - lib/alphred/struct.rb
96
108
  - lib/alphred/tasks.rb
97
- - lib/alphred/text.rb
98
109
  - lib/alphred/version.rb
99
- homepage: https://github.com/kejadlen/alph
110
+ homepage: https://github.com/kejadlen/alphred
100
111
  licenses:
101
112
  - MIT
102
113
  metadata: {}
@@ -1,59 +0,0 @@
1
- require 'fileutils'
2
- require 'json'
3
-
4
- module Alphred
5
- class Config
6
- def self.load(**defaults)
7
- config = new(**defaults)
8
- config.load!
9
- config
10
- end
11
-
12
- attr_reader :data
13
-
14
- def initialize(**defaults)
15
- @data = Hash[defaults.map {|k,v| [k.to_s, v.to_s] }]
16
- end
17
-
18
- def load!
19
- return unless File.exist?(path)
20
- data.merge!(JSON.load(File.open(path)))
21
- end
22
-
23
- def update!(json)
24
- data = self.data.merge(JSON.load(json))
25
- FileUtils.mkdir_p(File.dirname(path))
26
- File.write(path, JSON.dump(data), mode: ?w)
27
- end
28
-
29
- def [](key)
30
- data[key.to_s]
31
- end
32
-
33
- def filter_xml(filter=nil)
34
- filter ||= ''
35
-
36
- items = data.map do |key, value|
37
- title = if filter.empty?
38
- "Unset #{key}"
39
- else
40
- "Set #{key} to #{filter}"
41
- end
42
- Item.new(
43
- uid: key,
44
- arg: JSON.dump(key => filter),
45
- title: title,
46
- subtitle: self[key]
47
- )
48
- end
49
-
50
- Items.new(*items).to_xml
51
- end
52
-
53
- private
54
-
55
- def path
56
- File.join(ENV['alfred_workflow_data'], 'config.json')
57
- end
58
- end
59
- end
@@ -1,39 +0,0 @@
1
- require "builder"
2
-
3
- module Alphred
4
- class Icon
5
- VALID_TYPES = %i[ fileicon filetype ]
6
-
7
- attr_accessor *%i[ value type ]
8
-
9
- def initialize(**kwargs)
10
- raise ArgumentError.new("missing keyword: value") unless kwargs.has_key?(:value)
11
-
12
- @value = kwargs[:value]
13
- self.type = kwargs[:type] if kwargs.has_key?(:type)
14
- end
15
-
16
- def type=(type)
17
- raise ArgumentError.new("`type` must be one of #{VALID_TYPES}") unless type.nil? || VALID_TYPES.include?(type)
18
-
19
- @type = type
20
- end
21
-
22
- def to_xml(xml=nil)
23
- xml ||= Builder::XmlMarkup.new(indent: 2)
24
- attrs = {}
25
- attrs[:type] = self.type unless self.type.nil?
26
- xml.icon self.value, attrs
27
- end
28
- end
29
- end
30
-
31
- module Kernel
32
- def Icon(value)
33
- case value
34
- when Alphred::Icon then value
35
- when String then Alphred::Icon.new(value: value)
36
- when Hash then Alphred::Icon.new(**value)
37
- end
38
- end
39
- end
@@ -1,22 +0,0 @@
1
- require "builder"
2
-
3
- module Alphred
4
- class Mods
5
- MODS = %i[ shift fn ctrl alt cmd ]
6
-
7
- attr_accessor *MODS
8
-
9
- def initialize(**kwargs)
10
- MODS.each do |mod|
11
- self.instance_variable_set("@#{mod}", kwargs[mod]) if kwargs.has_key?(mod)
12
- end
13
- end
14
-
15
- def to_xml(xml)
16
- MODS.each do |mod|
17
- value = self.send(mod)
18
- xml.subtitle value, mod: mod unless value.nil?
19
- end
20
- end
21
- end
22
- end
@@ -1,17 +0,0 @@
1
- require "builder"
2
-
3
- module Alphred
4
- class Text
5
- attr_accessor *%i[ copy largetype ]
6
-
7
- def initialize(copy: nil, largetype: nil)
8
- @copy = copy
9
- @largetype = largetype
10
- end
11
-
12
- def to_xml(xml)
13
- xml.text copy, type: :copy unless self.copy.nil?
14
- xml.text largetype, type: :largetype unless self.largetype.nil?
15
- end
16
- end
17
- end