ursa 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 8343444cd1c5b84671c792baf81a687bf13c63a1
4
+ data.tar.gz: 8baff3d6099d245a71c8f9001e0d76727175f38d
5
+ SHA512:
6
+ metadata.gz: 948390dd7252b030a4430c437947506709b60c9360f2e3b6562c1ac35efceb8a847bdb77771b371b1e26f2f28e2008b97fd1e0d489d7237a675bd23091b5a08e
7
+ data.tar.gz: 8dc64412d124f6f831d662b2163ff2516c50af1ae98ea5f509896107ca36dc7e6fbbbc7d6541852c622689c08aa064d95c52a63461a8973fb22508fc8f868abe
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) [year] [fullname]
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1 @@
1
+ TODO: Write an awesome README here with examples
@@ -0,0 +1,22 @@
1
+ require 'rake/clean'
2
+ require 'pathname'
3
+
4
+ task :default => :prepare
5
+
6
+ desc 'Copy recipes to ~/.ursa/recipes'
7
+ task :prepare do
8
+ recipes_folder = File.join(Dir.home, '.ursa', 'recipes')
9
+ mkdir_p recipes_folder
10
+
11
+ Dir.glob('lib/ursa/recipes/*') do |file|
12
+ file_name = Pathname.new(file).basename
13
+ recipe_file = File.join(recipes_folder, file_name)
14
+
15
+ unless File.exist?(recipe_file)
16
+ recipe_content = File.read(file)
17
+ File.open(recipe_file, 'w') do |f|
18
+ f.write(recipe_content)
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'ursa'
4
+
5
+ def get_recipe_file(recipe_name)
6
+ file_name = File.join(Dir.home, '.ursa', 'recipes', recipe_name)
7
+ if File.exist?(file_name)
8
+ file_name
9
+ else
10
+ nil
11
+ end
12
+ end
13
+
14
+ def with_rb_extension(filename)
15
+ if File.extname(filename) != ''
16
+ filename
17
+ else
18
+ "#{filename}.rb"
19
+ end
20
+ end
21
+
22
+ recipe_name = with_rb_extension(ARGV.first)
23
+ recipe_file = get_recipe_file(recipe_name) || recipe_name
24
+
25
+ ursa = Ursa.new
26
+ ursa.instance_eval File.read(recipe_file)
27
+ ursa.execute_script
@@ -0,0 +1,119 @@
1
+ require_relative './ursa/cherry-tree/cherry-tree'
2
+ require 'forwardable'
3
+
4
+ class Statement
5
+ attr_accessor :open, :close
6
+
7
+ def initialize(open = '', close = '')
8
+ self.open = open
9
+ self.close = close
10
+ end
11
+ end
12
+
13
+ class AliasObject
14
+ extend Forwardable
15
+ attr_accessor :ursa
16
+
17
+ def_delegator :ursa, 'tell'
18
+ def_delegator :ursa, 'app'
19
+ def_delegator :ursa, 'raw'
20
+ def_delegator :ursa, 'send_key'
21
+ def_delegator :ursa, 'key'
22
+ def_delegator :ursa, 'key_and_kind'
23
+
24
+ def initialize(ursa)
25
+ self.ursa = ursa
26
+ end
27
+ end
28
+
29
+ class Ursa
30
+ attr_accessor :tree
31
+
32
+ KEY_CODES = %w{
33
+ A S D F H G Z X C V ISO_Section B Q W E R Y T 1
34
+ 2 3 4 6 5 Equal 9 7 Minus 8 0 RightBracket O U LeftBracket I P Return L J Quote K Semicolon Backslash Comma Slash N M Period Tab Space Grave Delete Escape Command Shift CapsLock Option Control RightShift RightOption RightControl Function F17 KeypadDecimal KeypadMultiply KeypadPlus KeypadClear VolumeUp VolumeDown Mute KeypadDivide KeypadEnter KeypadMinus F18 F19 KeypadEquals Keypad0 Keypad1 Keypad2 Keypad3 Keypad4 Keypad5 Keypad6 Keypad7 F20 Keypad8 Keypad9 JIS_Yen JIS_Underscore JIS_KeypadComma F5 F6 F7 F3 F8 F9 JIS_Eisu F11 JIS_Kana F13 F16 F14 F10 F12 F15 Help Home PageUp ForwardDelete F4 End F2 PageDown F1 LeftArrow RightArrow DownArrow UpArrow
35
+ }
36
+
37
+ KEY_ALIASES = {
38
+ :command => "command down",
39
+ :shift => "shift down",
40
+ :option => "option down"
41
+ }
42
+
43
+ def initialize
44
+ self.tree = CherryTree::Tree.new
45
+ end
46
+
47
+ def tell(name, to_statement = '', &block)
48
+ statement = if to_statement != ''
49
+ Statement.new "tell #{name} to #{to_statement}"
50
+ else
51
+ Statement.new "tell #{name}", "end tell"
52
+ end
53
+
54
+ tree.make_node(statement, &block)
55
+ end
56
+
57
+ def raw(statement, &block)
58
+ statement = Statement.new(statement)
59
+ tree.make_node(statement, &block)
60
+ end
61
+
62
+ def app(app_name)
63
+ "application \"#{app_name}\""
64
+ end
65
+
66
+ def send_key(code, modifiers)
67
+ "key code #{code} using {#{modifiers.join(', ')}}"
68
+ end
69
+
70
+ def key(letter)
71
+ key_found, _ = key_and_kind(letter)
72
+ key_found
73
+ end
74
+
75
+ def key_and_kind(letter)
76
+ case letter
77
+ when String
78
+ [KEY_CODES.index(letter), :normal]
79
+ when Symbol
80
+ [KEY_ALIASES[letter], :special]
81
+ end
82
+ end
83
+
84
+ def source_code
85
+ source_coder = CherryTree::SourceCoder.new tree, :indent => 4
86
+
87
+ source_coder.open do |node, indentation|
88
+ "#{node.data.open}\n"
89
+ end.close do |node, indentation|
90
+ "#{node.data.close}\n"
91
+ end
92
+
93
+ source_coder.source
94
+ end
95
+
96
+ def execute_script
97
+ `osascript -e "#{source_code.gsub('"', '\"')}"`
98
+ end
99
+
100
+ def delay(time)
101
+ raw "delay #{time}"
102
+ end
103
+
104
+ def include(package, alias_name)
105
+ alias_object = create_alias_object
106
+ self.send :define_singleton_method, alias_name do
107
+ alias_object.extend package
108
+ end
109
+ end
110
+
111
+ private
112
+
113
+ def create_alias_object
114
+ AliasObject.new(self)
115
+ end
116
+ end
117
+
118
+ require_relative './ursa/packages/system_events'
119
+ require_relative './ursa/packages/iterm'
@@ -0,0 +1,3 @@
1
+ require_relative './node'
2
+ require_relative './tree'
3
+ require_relative './transformers/source_coder'
@@ -0,0 +1,25 @@
1
+ module CherryTree
2
+ class Node
3
+ attr_accessor :children, :data, :parent, :deepness
4
+
5
+ DEEPNESS_SYMBOL = '----'
6
+
7
+ def initialize(data, parent, deepness)
8
+ self.data = data
9
+ self.parent = parent
10
+ self.deepness = deepness
11
+ self.children = []
12
+ end
13
+
14
+ def to_s
15
+ str = ""
16
+ str << "#{DEEPNESS_SYMBOL * deepness}#{DEEPNESS_SYMBOL}#{data}\n"
17
+ if children.any?
18
+ children.each do |child|
19
+ str << child.to_s
20
+ end
21
+ end
22
+ str
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,69 @@
1
+ class CherryTree::SourceCoder
2
+ attr_accessor :buffer, :tree, :open_block, :close_block, :indent
3
+
4
+ def initialize(tree, options = {})
5
+ self.tree = tree
6
+ self.buffer = ''
7
+ self.indent = options[:indent] || 0
8
+ end
9
+
10
+ def open(&block)
11
+ self.open_block = block
12
+ self
13
+ end
14
+
15
+ def close(&block)
16
+ self.close_block = block
17
+ self
18
+ end
19
+
20
+ def source
21
+ @source ||= get_source
22
+ end
23
+
24
+ private
25
+
26
+ attr_accessor :current_indentation, :current_node
27
+
28
+ def get_source(node = tree.root)
29
+ self.current_node = node
30
+
31
+ buffer_open_block if should_open_block?
32
+
33
+ buffer_node_children
34
+
35
+ self.current_node = node
36
+ buffer_close_block if should_close_block?
37
+
38
+ buffer
39
+ end
40
+
41
+ def buffer_node_children
42
+ children = current_node.children
43
+ children.each do |child|
44
+ get_source(child)
45
+ end
46
+ end
47
+
48
+ def buffer_open_block
49
+ buffer << "#{indentation}#{open_block.call(current_node)}"
50
+ end
51
+
52
+ def buffer_close_block
53
+ buffer << "#{indentation}#{close_block.call(current_node)}"
54
+ end
55
+
56
+ def should_close_block?
57
+ return false unless should_open_block?
58
+ close_code = close_block.call(current_node)
59
+ close_code && close_code.strip != ''
60
+ end
61
+
62
+ def should_open_block?
63
+ !current_node.data.nil?
64
+ end
65
+
66
+ def indentation
67
+ ' ' * indent * current_node.deepness
68
+ end
69
+ end
@@ -0,0 +1,37 @@
1
+ module CherryTree
2
+ class Tree
3
+ attr_accessor :current_deep_level, :current_parent, :root
4
+
5
+ def initialize
6
+ self.current_deep_level = 0
7
+ self.root = Node.new(nil, nil, current_deep_level)
8
+ self.current_parent = root
9
+ end
10
+
11
+ def to_s
12
+ root.to_s if root
13
+ end
14
+
15
+ def make_node(data)
16
+ node = Node.new(data, current_parent, current_deep_level)
17
+
18
+ if current_parent
19
+ current_parent.children << node
20
+ end
21
+
22
+ if block_given?
23
+ old_current_parent = self.current_parent
24
+
25
+ self.current_deep_level += 1
26
+ self.current_parent = node
27
+
28
+ yield
29
+
30
+ self.current_parent = old_current_parent
31
+ self.current_deep_level -= 1
32
+ end
33
+
34
+ node
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,34 @@
1
+ module Ursa::Packages
2
+ module ITerm
3
+ include Ursa::Packages::SystemEvents
4
+
5
+ def execute(*commands)
6
+ run_in_current_session do
7
+ commands.each do |command|
8
+ raw "write text \"#{command}\""
9
+ end
10
+ end
11
+ end
12
+
13
+ def run(*words)
14
+ execute words.map(&:to_s).join(' ')
15
+ end
16
+
17
+ def split_vertical
18
+ press_keys { command + shift + d }
19
+ end
20
+
21
+ def split_horizontal
22
+ press_keys { command + d }
23
+ end
24
+
25
+ def run_in_current_session
26
+ tell app('iTerm') do
27
+ tell 'the current terminal' do
28
+ raw "activate current session"
29
+ tell('the last session') { yield }
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,42 @@
1
+ module Ursa::Packages
2
+ class KeyDSL
3
+ attr_accessor :ursa, :normal_keys, :special_keys
4
+
5
+ def initialize(ursa)
6
+ self.ursa = ursa
7
+ self.normal_keys = []
8
+ self.special_keys = []
9
+ end
10
+
11
+ def method_missing(meth, *args, &block)
12
+ key, kind = ursa.key_and_kind(meth.to_sym)
13
+ if key.nil?
14
+ key, kind = ursa.key_and_kind(meth.to_s.upcase)
15
+ end
16
+
17
+ if kind == :normal
18
+ normal_keys << key
19
+ elsif kind == :special
20
+ special_keys << key
21
+ end
22
+ end
23
+ end
24
+
25
+ module SystemEvents
26
+ def press_keys(&key_block)
27
+ codes, modifiers = parse_key(key_block)
28
+
29
+ if codes.size == 1
30
+ code = codes.first
31
+ tell app('System Events'), send_key(code, modifiers)
32
+ end
33
+ end
34
+
35
+ def parse_key(key_block)
36
+ dsl = KeyDSL.new(self)
37
+ dsl.instance_eval &key_block
38
+
39
+ [dsl.normal_keys, dsl.special_keys]
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,26 @@
1
+ # This is a sample recipe
2
+
3
+ # It assumes that this is a rails project
4
+ # run in iTerm using Zeus, Guard and Sublime Text 2/3.
5
+
6
+ # I should make a more generic recipe later.
7
+ # This file is now in your home folder and Ursa
8
+ # will never attempt to replace your file so
9
+ # feel free to modify it with your own needs.
10
+
11
+ @location = ARGV[1]
12
+
13
+ include Ursa::Packages::ITerm, :iTerm
14
+
15
+ def jump_and_run(*commands)
16
+ iTerm.execute "cd #{@location}", *commands
17
+ end
18
+
19
+ iTerm.split_vertical
20
+ jump_and_run('zeus start')
21
+ iTerm.split_horizontal
22
+ jump_and_run('bundle exec guard')
23
+ iTerm.split_vertical
24
+ jump_and_run('zeus server')
25
+ iTerm.split_horizontal
26
+ jump_and_run("subl .")
@@ -0,0 +1,3 @@
1
+ module Ursa
2
+ VERSION = '0.0.1'
3
+ end
metadata ADDED
@@ -0,0 +1,74 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ursa
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Julio García
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-02-23 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rspec
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '2.14'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '2.14'
27
+ description: Ursa generates Applescript from Ruby Code allowing you to automate many
28
+ things in your mac without suffering with a somewhat strange language.
29
+ email: julioggonz@gmail.com
30
+ executables:
31
+ - ursa
32
+ extensions:
33
+ - Rakefile
34
+ extra_rdoc_files: []
35
+ files:
36
+ - LICENSE
37
+ - README.md
38
+ - Rakefile
39
+ - bin/ursa
40
+ - lib/ursa.rb
41
+ - lib/ursa/cherry-tree/cherry-tree.rb
42
+ - lib/ursa/cherry-tree/node.rb
43
+ - lib/ursa/cherry-tree/transformers/source_coder.rb
44
+ - lib/ursa/cherry-tree/tree.rb
45
+ - lib/ursa/packages/iterm.rb
46
+ - lib/ursa/packages/system_events.rb
47
+ - lib/ursa/recipes/openproject.rb
48
+ - lib/ursa/version.rb
49
+ homepage: http://github.com/juliogarciag/ursa
50
+ licenses:
51
+ - MIT
52
+ metadata: {}
53
+ post_install_message:
54
+ rdoc_options: []
55
+ require_paths:
56
+ - lib
57
+ required_ruby_version: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ required_rubygems_version: !ruby/object:Gem::Requirement
63
+ requirements:
64
+ - - ">="
65
+ - !ruby/object:Gem::Version
66
+ version: '0'
67
+ requirements: []
68
+ rubyforge_project:
69
+ rubygems_version: 2.2.0
70
+ signing_key:
71
+ specification_version: 4
72
+ summary: Programming-friendly Applescript creation.
73
+ test_files: []
74
+ has_rdoc: