repla 0.3.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.
Files changed (52) hide show
  1. checksums.yaml +7 -0
  2. data/lib/applescript/close_window.scpt +0 -0
  3. data/lib/applescript/create_window.scpt +0 -0
  4. data/lib/applescript/do_javascript.scpt +0 -0
  5. data/lib/applescript/exists.scpt +0 -0
  6. data/lib/applescript/hide_log.scpt +0 -0
  7. data/lib/applescript/load_html.scpt +0 -0
  8. data/lib/applescript/load_html_with_base_url.scpt +0 -0
  9. data/lib/applescript/load_plugin.scpt +0 -0
  10. data/lib/applescript/read_from_standard_input.scpt +0 -0
  11. data/lib/applescript/resource_path_for_plugin.scpt +0 -0
  12. data/lib/applescript/resource_url_for_plugin.scpt +0 -0
  13. data/lib/applescript/run_plugin.scpt +0 -0
  14. data/lib/applescript/run_plugin_in_split.scpt +0 -0
  15. data/lib/applescript/show_log.scpt +0 -0
  16. data/lib/applescript/split_id_in_window.scpt +0 -0
  17. data/lib/applescript/split_id_in_window_last.scpt +0 -0
  18. data/lib/applescript/toggle_log.scpt +0 -0
  19. data/lib/applescript/window_id_for_plugin.scpt +0 -0
  20. data/lib/repla/dependencies/css/style.css +15 -0
  21. data/lib/repla/dependencies/js/wcdependencies.js +10 -0
  22. data/lib/repla/dependencies/lib/controller.rb +34 -0
  23. data/lib/repla/dependencies/lib/model.rb +10 -0
  24. data/lib/repla/dependencies/lib/tester.rb +19 -0
  25. data/lib/repla/dependencies/lib/view.rb +19 -0
  26. data/lib/repla/dependencies/views/view.html.erb +25 -0
  27. data/lib/repla/dependencies.rb +34 -0
  28. data/lib/repla/extension_constants.rb +1 -0
  29. data/lib/repla/lib/constants.rb +11 -0
  30. data/lib/repla/lib/controller.rb +5 -0
  31. data/lib/repla/lib/module.rb +133 -0
  32. data/lib/repla/lib/view/erb.rb +17 -0
  33. data/lib/repla/lib/view/javascript.rb +45 -0
  34. data/lib/repla/lib/view/resources.rb +42 -0
  35. data/lib/repla/lib/view.rb +28 -0
  36. data/lib/repla/lib/window.rb +75 -0
  37. data/lib/repla/logger/test/Rakefile +20 -0
  38. data/lib/repla/logger/test/js/test_view_helper.js +3 -0
  39. data/lib/repla/logger/test/lib/test_constants.rb +8 -0
  40. data/lib/repla/logger/test/lib/test_view_helper.rb +27 -0
  41. data/lib/repla/logger/test/run_tests.sh +3 -0
  42. data/lib/repla/logger/test/tc_logger.rb +173 -0
  43. data/lib/repla/logger.rb +69 -0
  44. data/lib/repla/repl/css/style.css +20 -0
  45. data/lib/repla/repl/js/wcrepl.js +17 -0
  46. data/lib/repla/repl/lib/input_controller.rb +18 -0
  47. data/lib/repla/repl/lib/output_controller.rb +19 -0
  48. data/lib/repla/repl/lib/view.rb +68 -0
  49. data/lib/repla/repl/view/view.html.erb +12 -0
  50. data/lib/repla/repl.rb +49 -0
  51. data/lib/repla.rb +9 -0
  52. metadata +92 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 1b80e1592a3dc429896f001bda2bddff25b7e3d8
4
+ data.tar.gz: fdc62f4bd40eee40bd310317e0a69c94aed98c57
5
+ SHA512:
6
+ metadata.gz: cc65843d273f506f347478d436fbc9ccc12e07f49621be18dba68f2f3428907c349c140e83b2c20c5d6ad70bdb0e3d2e46b727a48ee5b7ebe3130a1e2027144e
7
+ data.tar.gz: 29484bdba1f0240d71ff699a530a938756f2911473472d9d5efe102da1657d46e3f128b6a77573ced49fce80949932eb18fa1b09b71c2beb5942e4ef440ac7ec
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
@@ -0,0 +1,15 @@
1
+ body, h5 {
2
+ font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
3
+ font-size: 13px;
4
+ }
5
+ h5 {
6
+ font-weight: normal;
7
+ color: red;
8
+ }
9
+ blockquote {
10
+ margin-left: 2em;
11
+ }
12
+ code {
13
+ background-color: #DBE2EC;
14
+ font-family: "Menlo", monospace;
15
+ }
@@ -0,0 +1,10 @@
1
+ function addMissingDependency(name, type, installationInstructions) {
2
+ var source = $("#dependency-template").html();
3
+ var template = Handlebars.compile(source);
4
+ var data = {
5
+ name: name,
6
+ type: type,
7
+ installationInstructions: installationInstructions
8
+ };
9
+ $(template(data)).appendTo("body");
10
+ }
@@ -0,0 +1,34 @@
1
+ require_relative 'tester'
2
+ require_relative 'model'
3
+ require_relative 'view'
4
+
5
+ module Repla::Dependencies
6
+
7
+ class Controller < Repla::Controller
8
+
9
+ def initialize
10
+ @view = View.new
11
+ end
12
+
13
+ def missing_dependency(dependency)
14
+ name = dependency.name
15
+ type = self.class.string_for_type(dependency.type)
16
+ options = dependency.options
17
+ if options.has_key?(:installation_instructions)
18
+ installation_instructions = options[:installation_instructions]
19
+ end
20
+ @view.add_missing_dependency(name, type, installation_instructions)
21
+ end
22
+
23
+ private
24
+
25
+ def self.string_for_type(type)
26
+ case type
27
+ when :shell_command
28
+ return "shell command"
29
+ end
30
+ nil
31
+ end
32
+
33
+ end
34
+ end
@@ -0,0 +1,10 @@
1
+ module Repla::Dependencies
2
+ class Dependency
3
+ attr_reader :name, :type, :options
4
+ def initialize(name, type, options = {})
5
+ @name = name
6
+ @type = type
7
+ @options = options
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,19 @@
1
+ module Repla::Dependencies
2
+ module Tester
3
+ def self.check(name, type)
4
+ case type
5
+ when :shell_command
6
+ return check_shell_command(name)
7
+ end
8
+ end
9
+
10
+ private
11
+
12
+ require 'shellwords'
13
+ def self.check_shell_command(name)
14
+ command = "type -a #{Shellwords.escape(name)} > /dev/null 2>&1"
15
+ system(command)
16
+ end
17
+
18
+ end
19
+ end
@@ -0,0 +1,19 @@
1
+ module Repla::Dependencies
2
+
3
+ class View < Repla::View
4
+ BASE_DIRECTORY = File.join(File.dirname(__FILE__), '..')
5
+ VIEWS_DIRECTORY = File.join(BASE_DIRECTORY, "views")
6
+ VIEW_TEMPLATE = File.join(VIEWS_DIRECTORY, 'view.html.erb')
7
+
8
+ def initialize
9
+ super
10
+ self.base_url_path = File.expand_path(BASE_DIRECTORY)
11
+ load_erb_from_path(VIEW_TEMPLATE)
12
+ end
13
+
14
+ ADD_MISSING_DEPENDENCY_FUNCTION = "addMissingDependency"
15
+ def add_missing_dependency(name, type, installation_instructions = nil)
16
+ do_javascript_function(ADD_MISSING_DEPENDENCY_FUNCTION, [name, type, installation_instructions])
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,25 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <title><%= title %></title>
6
+ <%= shared_stylesheet_link_tag "raster" %>
7
+ <link rel="stylesheet" href="css/style.css" />
8
+ <script id="dependency-template" type="text/x-handlebars-template">
9
+ <section>
10
+ <header>
11
+ <h5>Dependency <span class="type">{{type}}</span> <code class="name">{{name}}</code> not found.</h5>
12
+ </header>
13
+ {{#if installationInstructions}}
14
+ <p><blockquote class="installation">To install <code>{{name}}</code>: {{{installationInstructions}}}</blockquote></p>
15
+ {{/if}}
16
+ </section>
17
+ </script>
18
+ <%= shared_javascript_include_tag "handlebars" %>
19
+ <%= shared_javascript_include_tag "zepto" %>
20
+ <script type="text/javascript" src="js/wcdependencies.js"></script>
21
+ </head>
22
+ <body>
23
+
24
+ </body>
25
+ </html>
@@ -0,0 +1,34 @@
1
+ require_relative 'extension_constants'
2
+ require REPLA_FILE
3
+
4
+ module Repla::Dependencies
5
+ class Checker
6
+ require_relative 'dependencies/lib/model'
7
+ require_relative 'dependencies/lib/controller'
8
+
9
+ def check_dependencies(dependencies)
10
+ passed = true
11
+ dependencies.each { |dependency|
12
+ dependency_passed = check(dependency)
13
+ passed = false unless dependency_passed
14
+ }
15
+ passed
16
+ end
17
+
18
+ def check(dependency)
19
+ name = dependency.name
20
+ type = dependency.type
21
+ passed = Tester::check(name, type)
22
+ controller.missing_dependency(dependency) unless passed
23
+ passed
24
+ end
25
+
26
+ private
27
+
28
+ def controller
29
+ @controller ||= Controller.new
30
+ end
31
+
32
+ end
33
+
34
+ end
@@ -0,0 +1 @@
1
+ REPLA_FILE = File.join(File.dirname(__FILE__), "../repla")
@@ -0,0 +1,11 @@
1
+ module Repla
2
+ # Keys
3
+ PLUGIN_NAME_KEY = 'WC_PLUGIN_NAME'
4
+ SPLIT_ID_KEY = 'WC_SPLIT_ID'
5
+ WINDOW_ID_KEY = 'WC_WINDOW_ID'
6
+ SHARED_RESOURCES_PATH_KEY = 'WC_SHARED_RESOURCES_PATH'
7
+ SHARED_RESOURCES_URL_KEY = 'WC_SHARED_RESOURCES_URL'
8
+
9
+ # Directories
10
+ APPLESCRIPT_DIRECTORY = File.join(File.dirname(__FILE__), "..", "..", "applescript")
11
+ end
@@ -0,0 +1,5 @@
1
+ module Repla
2
+ class Controller
3
+ attr_reader :view
4
+ end
5
+ end
@@ -0,0 +1,133 @@
1
+ require 'Shellwords'
2
+ module Repla
3
+ LOAD_PLUGIN_SCRIPT = File.join(APPLESCRIPT_DIRECTORY, "load_plugin.scpt")
4
+ def self.load_plugin(path)
5
+ self.run_applescript(LOAD_PLUGIN_SCRIPT, [path])
6
+ end
7
+
8
+ EXISTS_SCRIPT = File.join(APPLESCRIPT_DIRECTORY, "exists.scpt")
9
+ def self.application_exists
10
+ result = self.run_applescript(EXISTS_SCRIPT)
11
+ result == "true" ? true : false
12
+ end
13
+
14
+ RUN_PLUGIN_SCRIPT = File.join(APPLESCRIPT_DIRECTORY, "run_plugin.scpt")
15
+ def self.run_plugin(name, directory = nil, arguments = nil)
16
+ parameters = [name]
17
+ parameters.push(directory) unless directory.nil?
18
+ parameters += arguments unless arguments.nil?
19
+ self.run_applescript(RUN_PLUGIN_SCRIPT, parameters)
20
+ end
21
+
22
+ RUN_PLUGIN_IN_SPLIT_SCRIPT = File.join(APPLESCRIPT_DIRECTORY, "run_plugin_in_split.scpt")
23
+ def self.run_plugin_in_split(name, window_id, split_id)
24
+ parameters = [name, window_id, split_id]
25
+ self.run_applescript(RUN_PLUGIN_IN_SPLIT_SCRIPT, parameters)
26
+ end
27
+
28
+ WINDOW_ID_FOR_PLUGIN_SCRIPT = File.join(APPLESCRIPT_DIRECTORY, "window_id_for_plugin.scpt")
29
+ def self.window_id_for_plugin(name)
30
+ self.run_applescript(WINDOW_ID_FOR_PLUGIN_SCRIPT, [name])
31
+ end
32
+
33
+ SPLIT_ID_IN_WINDOW_SCRIPT = File.join(APPLESCRIPT_DIRECTORY, "split_id_in_window.scpt")
34
+ def self.split_id_in_window(window_id, pluginName = nil)
35
+ arguments = [window_id]
36
+ arguments.push(pluginName) unless pluginName.nil?
37
+ self.run_applescript(SPLIT_ID_IN_WINDOW_SCRIPT, arguments)
38
+ end
39
+
40
+ SPLIT_ID_IN_WINDOW_LAST_SCRIPT = File.join(APPLESCRIPT_DIRECTORY, "split_id_in_window_last.scpt")
41
+ def self.split_id_in_window_last(window_id)
42
+ arguments = [window_id]
43
+ self.run_applescript(SPLIT_ID_IN_WINDOW_LAST_SCRIPT, arguments)
44
+ end
45
+
46
+ CREATE_WINDOW_SCRIPT = File.join(APPLESCRIPT_DIRECTORY, "create_window.scpt")
47
+ def self.create_window
48
+ self.run_applescript(CREATE_WINDOW_SCRIPT)
49
+ end
50
+
51
+ # Shared Resources
52
+
53
+ RESOURCE_PATH_FOR_PLUGIN_SCRIPT = File.join(APPLESCRIPT_DIRECTORY, "resource_path_for_plugin.scpt")
54
+ def self.resource_path_for_plugin(name)
55
+ self.run_applescript(RESOURCE_PATH_FOR_PLUGIN_SCRIPT, [name])
56
+ end
57
+
58
+ # Shared Resource Path
59
+
60
+ SHARED_RESOURCES_PLUGIN_NAME = "Shared Resources"
61
+ SHARED_TEST_RESOURCES_PLUGIN_NAME = "Shared Test Resources"
62
+ def self.shared_resources_path
63
+ resource_path_for_plugin(SHARED_RESOURCES_PLUGIN_NAME)
64
+ end
65
+ def self.shared_test_resources_path
66
+ resource_path_for_plugin(SHARED_TEST_RESOURCES_PLUGIN_NAME)
67
+ end
68
+
69
+ def self.shared_resource(resource)
70
+ File.join(self.shared_resources_path, resource)
71
+ end
72
+ def self.shared_test_resource(resource)
73
+ File.join(self.shared_test_resources_path, resource)
74
+ end
75
+
76
+ # Shared Resource URL
77
+
78
+ RESOURCE_URL_FOR_PLUGIN_SCRIPT = File.join(APPLESCRIPT_DIRECTORY, "resource_url_for_plugin.scpt")
79
+ def self.resource_url_for_plugin(name)
80
+ self.run_applescript(RESOURCE_URL_FOR_PLUGIN_SCRIPT, [name])
81
+ end
82
+ def self.shared_resources_url
83
+ resource_url_for_plugin(SHARED_RESOURCES_PLUGIN_NAME)
84
+ end
85
+
86
+ private
87
+
88
+ def self.run_applescript(script, arguments = nil)
89
+ command = "osascript #{script.shell_escape}"
90
+
91
+ if arguments
92
+ command += " " + arguments.compact.map(&:to_s).map(&:shell_escape).join(' ')
93
+ end
94
+
95
+ result = `#{command}`
96
+
97
+ result.chomp!
98
+
99
+ return nil if result.empty?
100
+ return result.to_i if result.is_integer?
101
+ return result.to_f if result.is_float?
102
+
103
+ result
104
+ end
105
+
106
+ class ::String
107
+ def is_float?
108
+ true if Float(self) rescue false
109
+ end
110
+
111
+ def is_integer?
112
+ self.to_i.to_s == self
113
+ end
114
+
115
+ def shell_escape
116
+ Shellwords.escape(self)
117
+ end
118
+
119
+ def shell_escape!
120
+ replace(shell_escape)
121
+ end
122
+
123
+ end
124
+
125
+ class ::Float
126
+ alias_method :javascript_argument, :to_s
127
+ end
128
+
129
+ class ::Integer
130
+ alias_method :javascript_argument, :to_s
131
+ end
132
+
133
+ end
@@ -0,0 +1,17 @@
1
+ module Repla
2
+ class View < Window
3
+
4
+ require 'erb'
5
+
6
+ def load_erb_from_path(path)
7
+ erb = File.new(path).read
8
+ load_erb(erb)
9
+ end
10
+
11
+ def load_erb(erb)
12
+ template = ERB.new(erb, nil, '-')
13
+ html = template.result(binding)
14
+ load_html(html)
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,45 @@
1
+ module Repla
2
+ class View < Window
3
+
4
+ def do_javascript_function(function, arguments = nil)
5
+ javascript = self.class.javascript_function(function, arguments)
6
+ do_javascript(javascript)
7
+ end
8
+
9
+ def self.javascript_function(function, arguments = nil)
10
+ function = function.dup
11
+ function << '('
12
+
13
+ if arguments
14
+ arguments.each { |argument|
15
+ if argument
16
+ function << argument.javascript_argument
17
+ else
18
+ function << "null"
19
+ end
20
+ function << ', '
21
+ }
22
+ function = function[0...-2]
23
+ end
24
+
25
+ function << ');'
26
+ end
27
+
28
+ private
29
+
30
+ class ::String
31
+ def javascript_argument
32
+ "'#{self.javascript_escape}'"
33
+ end
34
+
35
+ def javascript_escape
36
+ self.gsub('\\', "\\\\\\\\").gsub("\n", "\\\\n").gsub("'", "\\\\'")
37
+ end
38
+
39
+ def javascript_escape!
40
+ replace(self.javascript_escape)
41
+ end
42
+ end
43
+
44
+ end
45
+ end
@@ -0,0 +1,42 @@
1
+ module Repla
2
+ class View < Window
3
+ require 'open-uri'
4
+
5
+ require_relative "../constants"
6
+ require_relative "../module"
7
+
8
+ attr_accessor :title
9
+
10
+ CSS_EXTENSION = ".css"
11
+ CSS_PATH_COMPONENT = "css/"
12
+ def shared_stylesheet_link_tag(resource)
13
+ uri = URI.join(shared_resources_url, CSS_PATH_COMPONENT, resource + CSS_EXTENSION)
14
+ stylesheet_link_tag(uri.to_s)
15
+ end
16
+
17
+ def stylesheet_link_tag(url)
18
+ "<link rel=\"stylesheet\" href=\"#{url}\" />"
19
+ end
20
+
21
+ JS_EXTENSION = ".js"
22
+ JS_PATH_COMPONENT = "js/"
23
+ def shared_javascript_include_tag(resource)
24
+ uri = URI.join(shared_resources_url, JS_PATH_COMPONENT, resource + JS_EXTENSION)
25
+ javascript_include_tag(uri.to_s)
26
+ end
27
+
28
+ def javascript_include_tag(url)
29
+ "<script type=\"text/javascript\" src=\"#{url}\"></script>"
30
+ end
31
+
32
+ def title
33
+ @title ||= ENV.has_key?(PLUGIN_NAME_KEY) ? ENV[PLUGIN_NAME_KEY] : nil
34
+ end
35
+
36
+ private
37
+
38
+ def shared_resources_url
39
+ @shared_resources_url || ENV.has_key?(SHARED_RESOURCES_URL_KEY) ? ENV[SHARED_RESOURCES_URL_KEY] : Repla::shared_resources_url
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,28 @@
1
+ require_relative "window"
2
+ require_relative "view/javascript"
3
+ require_relative "view/erb"
4
+ require_relative "view/resources"
5
+
6
+ module Repla
7
+ class View < Window
8
+
9
+ # Properties
10
+ def initialize(window_id = nil, view_id = nil)
11
+ super(window_id)
12
+ @view_id = view_id
13
+ end
14
+
15
+ def view_id
16
+ @view_id ||= ENV.has_key?(SPLIT_ID_KEY) ? ENV[SPLIT_ID_KEY] : split_id
17
+ end
18
+
19
+ private
20
+
21
+ # Web
22
+
23
+ def arguments_with_target(arguments)
24
+ super(arguments).push(view_id)
25
+ end
26
+
27
+ end
28
+ end
@@ -0,0 +1,75 @@
1
+ module Repla
2
+ class Window
3
+ require_relative "constants"
4
+
5
+ attr_writer :base_url
6
+
7
+ def initialize(window_id = nil)
8
+ @window_id = window_id
9
+ end
10
+
11
+ # Properties
12
+
13
+ def base_url_path=(value)
14
+ @base_url = "file://" + value
15
+ end
16
+
17
+ def window_id
18
+ @window_id ||= ENV.has_key?(WINDOW_ID_KEY) ? ENV[WINDOW_ID_KEY] : Repla::create_window
19
+ end
20
+
21
+ # Web
22
+
23
+ LOADHTML_SCRIPT = File.join(APPLESCRIPT_DIRECTORY, "load_html.scpt")
24
+ LOADHTMLWITHBASEURL_SCRIPT = File.join(APPLESCRIPT_DIRECTORY, "load_html_with_base_url.scpt")
25
+ def load_html(html)
26
+ arguments = [html]
27
+
28
+ script = LOADHTML_SCRIPT
29
+
30
+ if @base_url
31
+ script = LOADHTMLWITHBASEURL_SCRIPT
32
+ arguments.push(@base_url)
33
+ end
34
+
35
+ run_script(script, arguments)
36
+ end
37
+
38
+ DOJAVASCRIPT_SCRIPT = File.join(APPLESCRIPT_DIRECTORY, "do_javascript.scpt")
39
+ def do_javascript(javascript)
40
+ run_script(DOJAVASCRIPT_SCRIPT, [javascript])
41
+ end
42
+
43
+ READ_FROM_STANDARD_INPUT_SCRIPT = File.join(APPLESCRIPT_DIRECTORY, "read_from_standard_input.scpt")
44
+ def read_from_standard_input(text)
45
+ run_script(READ_FROM_STANDARD_INPUT_SCRIPT, [text])
46
+ end
47
+
48
+ # Window
49
+
50
+ CLOSEWINDOW_SCRIPT = File.join(APPLESCRIPT_DIRECTORY, "close_window.scpt")
51
+ def close
52
+ Repla::run_applescript(CLOSEWINDOW_SCRIPT, [window_id])
53
+ end
54
+
55
+ def split_id
56
+ Repla::split_id_in_window(window_id)
57
+ end
58
+
59
+ def split_id_last
60
+ Repla::split_id_in_window_last(window_id)
61
+ end
62
+
63
+ private
64
+
65
+ def run_script(script, arguments = [])
66
+ arguments = arguments_with_target(arguments)
67
+ Repla::run_applescript(script, arguments)
68
+ end
69
+
70
+ def arguments_with_target(arguments)
71
+ arguments.push(window_id)
72
+ end
73
+
74
+ end
75
+ end
@@ -0,0 +1,20 @@
1
+ require 'shellwords'
2
+ require 'repla'
3
+ require Repla::shared_test_resource("ruby/test_constants")
4
+ require Repla::Tests::TEST_HELPER_FILE
5
+
6
+ task :default => ['logger:tests']
7
+
8
+ namespace :logger do
9
+
10
+ task :tests => [:clean_up]
11
+
12
+ task :test_logger do
13
+ logger_tests_file = File.join(File.dirname(__FILE__), "tc_logger.rb")
14
+ ruby Shellwords.escape(logger_tests_file)
15
+ end
16
+
17
+ task :clean_up => [:test_logger] do
18
+ Repla::Tests::Helper::quit
19
+ end
20
+ end
@@ -0,0 +1,3 @@
1
+ function innerTextOfBodyChildAtIndex(index) {
2
+ return document.body.children[index].innerText;
3
+ }
@@ -0,0 +1,8 @@
1
+ require_relative "../../../extension_constants"
2
+
3
+ TEST_CLASS_JAVASCRIPT = "document.body.lastChild.classList[0]"
4
+ TEST_MESSAGE_JAVASCRIPT = "document.body.lastChild.innerText"
5
+ TEST_MESSAGE_COUNT_JAVASCRIPT = "document.body.children.length"
6
+
7
+ TEST_JAVASCRIPT_DIRECTORY = File.join(File.dirname(__FILE__), "..", "js")
8
+ TEST_JAVASCRIPT_FILE = File.join(TEST_JAVASCRIPT_DIRECTORY, "test_view_helper.js")
@@ -0,0 +1,27 @@
1
+ require_relative 'test_constants'
2
+
3
+ class TestViewHelper
4
+
5
+ def initialize(window_id, view_id)
6
+ @view = Repla::View.new(window_id, view_id)
7
+ javascript = File.read(TEST_JAVASCRIPT_FILE)
8
+ @view.do_javascript(javascript)
9
+ end
10
+
11
+ def log_message_at_index(index)
12
+ @view.do_javascript_function('innerTextOfBodyChildAtIndex', [index])
13
+ end
14
+
15
+ def number_of_log_messages
16
+ @view.do_javascript(TEST_MESSAGE_COUNT_JAVASCRIPT)
17
+ end
18
+
19
+ def last_log_message
20
+ @view.do_javascript(TEST_MESSAGE_JAVASCRIPT)
21
+ end
22
+
23
+ def last_log_class
24
+ @view.do_javascript(TEST_CLASS_JAVASCRIPT)
25
+ end
26
+
27
+ end
@@ -0,0 +1,3 @@
1
+ #!/bin/sh
2
+
3
+ rake
@@ -0,0 +1,173 @@
1
+ #!/System/Library/Frameworks/Ruby.framework/Versions/2.3/usr/bin/ruby
2
+
3
+ require "test/unit"
4
+
5
+ require_relative "lib/test_constants"
6
+ require REPLA_FILE
7
+ require Repla::shared_test_resource("ruby/test_constants")
8
+ require Repla::Tests::TEST_HELPER_FILE
9
+
10
+ require_relative "lib/test_view_helper"
11
+ require_relative "../../logger"
12
+
13
+
14
+ class TestConstants < Test::Unit::TestCase
15
+
16
+ def test_constants
17
+ message_prefix = Repla::Logger::MESSAGE_PREFIX
18
+ assert_not_nil(message_prefix, "The message prefix should not be nil.")
19
+ error_prefix = Repla::Logger::ERROR_PREFIX
20
+ assert_not_nil(message_prefix, "The error prefix should not be nil.")
21
+ end
22
+
23
+ end
24
+
25
+
26
+ class TestUnintializedLogger < Test::Unit::TestCase
27
+
28
+ def teardown
29
+ Repla::Tests::Helper::quit
30
+ assert(!Repla::Tests::Helper::is_running, "The application should not be running.")
31
+ end
32
+
33
+ def test_uninitialized_logger
34
+ logger = Repla::Logger.new
35
+
36
+ # Test Message
37
+ message = "Testing log message"
38
+ logger.info(message)
39
+ sleep Repla::Tests::TEST_PAUSE_TIME # Pause for output to be processed
40
+
41
+ # Make sure the log messages before accessing the logger's `view_id` and `window_id` because those run the logger.
42
+ # This test should test logging a message and running the logger itself simultaneously.
43
+ # This is why the `TestViewHelper` is intialized after logging the message.
44
+ test_view_helper = TestViewHelper.new(logger.window_id, logger.view_id)
45
+
46
+ test_message = test_view_helper.last_log_message
47
+ assert_equal(message, test_message, "The messages should match")
48
+ test_class = test_view_helper.last_log_class
49
+ assert_equal("message", test_class, "The classes should match")
50
+
51
+ end
52
+
53
+ end
54
+
55
+
56
+ class TestLogger < Test::Unit::TestCase
57
+
58
+ def setup
59
+ @logger = Repla::Logger.new
60
+ @logger.show
61
+ @test_view_helper = TestViewHelper.new(@logger.window_id, @logger.view_id)
62
+ end
63
+
64
+ def teardown
65
+ Repla::Tests::Helper::quit
66
+ assert(!Repla::Tests::Helper::is_running, "The application should not be running.")
67
+ end
68
+
69
+ def test_logger
70
+ test_count = 0
71
+
72
+ # Test Error
73
+ message = "Testing log error"
74
+ @logger.error(message)
75
+ sleep Repla::Tests::TEST_PAUSE_TIME # Pause for output to be processed
76
+ test_message = @test_view_helper.last_log_message
77
+ assert_equal(message, test_message, "The messages should match")
78
+ test_class = @test_view_helper.last_log_class
79
+ assert_equal("error", test_class, "The classes should match")
80
+ result_count = @test_view_helper.number_of_log_messages
81
+ test_count += 1
82
+ assert_equal(test_count, result_count, "The number of log messages should match")
83
+
84
+ # Test Message
85
+ message = "Testing log message"
86
+ @logger.info(message)
87
+ sleep Repla::Tests::TEST_PAUSE_TIME # Pause for output to be processed
88
+ test_message = @test_view_helper.last_log_message
89
+ assert_equal(message, test_message, "The messages should match")
90
+ test_class = @test_view_helper.last_log_class
91
+ assert_equal("message", test_class, "The classes should match")
92
+ result_count = @test_view_helper.number_of_log_messages
93
+ test_count += 1
94
+ assert_equal(test_count, result_count, "The number of log messages should match")
95
+
96
+ # Test Only Error Prefix
97
+ message = Repla::Logger::ERROR_PREFIX.rstrip # Note the trailing whitespace is trimmed
98
+ @logger.info(message)
99
+ sleep Repla::Tests::TEST_PAUSE_TIME # Pause for output to be processed
100
+ test_message = @test_view_helper.last_log_message
101
+ assert_equal(message, test_message, "The messages should match")
102
+ test_class = @test_view_helper.last_log_class
103
+ assert_equal("message", test_class, "The classes should match")
104
+ result_count = @test_view_helper.number_of_log_messages
105
+ test_count += 1
106
+ assert_equal(test_count, result_count, "The number of log messages should match")
107
+
108
+ # Test Only Message Prefix
109
+ message = Repla::Logger::MESSAGE_PREFIX.rstrip # Note the trailing whitespace is trimmed
110
+ @logger.info(message)
111
+ sleep Repla::Tests::TEST_PAUSE_TIME # Pause for output to be processed
112
+ test_message = @test_view_helper.last_log_message
113
+ assert_equal(message, test_message, "The messages should match")
114
+ test_class = @test_view_helper.last_log_class
115
+ assert_equal("message", test_class, "The classes should match")
116
+ result_count = @test_view_helper.number_of_log_messages
117
+ test_count += 1
118
+ assert_equal(test_count, result_count, "The number of log messages should match")
119
+
120
+ # Test Blank Spaces
121
+ @logger.info(" \t")
122
+ sleep Repla::Tests::TEST_PAUSE_TIME # Pause for output to be processed
123
+ test_message = @test_view_helper.last_log_message()
124
+ assert_equal(message, test_message, "The messages should match")
125
+ test_class = @test_view_helper.last_log_class()
126
+ assert_equal("message", test_class, "The classes should match")
127
+
128
+ # Test Empty String
129
+ @logger.info("")
130
+ sleep Repla::Tests::TEST_PAUSE_TIME # Pause for output to be processed
131
+ test_message = @test_view_helper.last_log_message()
132
+ assert_equal(message, test_message, "The messages should match")
133
+ test_class = @test_view_helper.last_log_class()
134
+ assert_equal("message", test_class, "The classes should match")
135
+
136
+ # TODO: Also add the following tests the `Log.wcplugin`
137
+
138
+ # Test Whitespace
139
+ # White space to the left should be preserved, whitespace to the right should be removed
140
+ # This test fails because retrieving the `innerText` doesn't preserve whitepace.
141
+
142
+ # message = "\t Testing log message"
143
+ # @logger.info(message + "\t ")
144
+ # sleep Repla::Tests::TEST_PAUSE_TIME # Pause for output to be processed
145
+ # test_message = @test_view_helper.last_log_message
146
+ # assert_equal(message, test_message, "The messages should match")
147
+ # test_class = @test_view_helper.last_log_class
148
+ # assert_equal("message", test_class, "The classes should match")
149
+ # result_count = @test_view_helper.number_of_log_messages
150
+ # test_count += 1
151
+ # assert_equal(test_count, result_count, "The number of log messages should match")
152
+ end
153
+
154
+ def test_long_input
155
+ message = %q(
156
+ Line 1
157
+
158
+ Line 2
159
+ Line 3
160
+ )
161
+ @logger.info(message)
162
+ sleep Repla::Tests::TEST_PAUSE_TIME * 2 # Pause for output to be processed
163
+ result_count = @test_view_helper.number_of_log_messages
164
+ assert_equal(result_count, 3, "The number of log messages should match")
165
+
166
+ (1..3).each { |i|
167
+ result = @test_view_helper.log_message_at_index(i - 1)
168
+ test_result = "Line #{i}"
169
+ assert_equal(result, test_result, "The number of log messages should match")
170
+ }
171
+ end
172
+
173
+ end
@@ -0,0 +1,69 @@
1
+ require_relative 'extension_constants'
2
+ require REPLA_FILE
3
+
4
+ module Repla
5
+
6
+ class Logger
7
+ MESSAGE_PREFIX = 'MESSAGE '
8
+ ERROR_PREFIX = 'ERROR '
9
+ LOG_PLUGIN_NAME = 'Log'
10
+
11
+ # Toggle
12
+
13
+ SHOW_LOG_SCRIPT = File.join(APPLESCRIPT_DIRECTORY, "show_log.scpt")
14
+ def show
15
+ Repla::run_applescript(SHOW_LOG_SCRIPT, [window_id])
16
+ end
17
+
18
+ HIDE_LOG_SCRIPT = File.join(APPLESCRIPT_DIRECTORY, "hide_log.scpt")
19
+ def hide
20
+ Repla::run_applescript(HIDE_LOG_SCRIPT, [window_id])
21
+ end
22
+
23
+ TOGGLE_LOG_SCRIPT = File.join(APPLESCRIPT_DIRECTORY, "toggle_log.scpt")
24
+ def toggle
25
+ Repla::run_applescript(TOGGLE_LOG_SCRIPT, [window_id])
26
+ end
27
+
28
+ # Messages
29
+
30
+ def info(message)
31
+ message = message.dup
32
+ message.gsub!(%r{^}, MESSAGE_PREFIX) # Prefix all lines
33
+ # Strip trailing white space
34
+ # Add a line break
35
+ log_message(message)
36
+ end
37
+
38
+ def error(message)
39
+ message = message.dup
40
+ message.gsub!(%r{^}, ERROR_PREFIX)
41
+ log_message(message)
42
+ end
43
+
44
+ # Properties
45
+
46
+ def window_id
47
+ @window_id ||= ENV.has_key?(WINDOW_ID_KEY) ? ENV[WINDOW_ID_KEY] : Repla::create_window
48
+ end
49
+
50
+ def view_id
51
+ @view_id ||= Repla::split_id_in_window(window_id, LOG_PLUGIN_NAME)
52
+ return @view_id unless @view_id.nil?
53
+
54
+ @view_id = Repla::split_id_in_window_last(window_id)
55
+ Repla::run_plugin_in_split(LOG_PLUGIN_NAME, window_id, @view_id)
56
+ @view_id
57
+ end
58
+
59
+ private
60
+
61
+ READ_FROM_STANDARD_INPUT_SCRIPT = File.join(APPLESCRIPT_DIRECTORY, "read_from_standard_input.scpt")
62
+ def log_message(message)
63
+ message.rstrip!
64
+ message += "\n"
65
+ Repla::run_applescript(READ_FROM_STANDARD_INPUT_SCRIPT, [message, window_id, view_id])
66
+ end
67
+
68
+ end
69
+ end
@@ -0,0 +1,20 @@
1
+ body {
2
+ font-family: "Menlo", monospace;
3
+ font-size: 13px;
4
+ }
5
+ li {
6
+ list-style: none;
7
+ white-space: pre-wrap;
8
+ }
9
+ pre {
10
+ position: relative;
11
+ padding-left: 18px;
12
+ }
13
+ pre.output code:before
14
+ {
15
+ content: '>';
16
+ font-weight: bold;
17
+ left: 7px;
18
+ position: absolute;
19
+ opacity: 0.5;
20
+ }
@@ -0,0 +1,17 @@
1
+ var WcREPL = {
2
+ addCode: function(code, source) {
3
+ var template = Handlebars.compile(source);
4
+ var data = {
5
+ code: code
6
+ };
7
+ return $(template(data)).appendTo("body");
8
+ },
9
+ addInput: function(code) {
10
+ var source = $("#input-template").html();
11
+ this.addCode(code, source);
12
+ },
13
+ addOutput: function(code) {
14
+ var source = $("#output-template").html();
15
+ this.addCode(code, source);
16
+ }
17
+ }
@@ -0,0 +1,18 @@
1
+ module Repla::REPL
2
+ class InputController < Repla::Controller
3
+
4
+ attr_accessor :view
5
+ def initialize(view)
6
+ @view = view
7
+ end
8
+
9
+ def parse_input(input)
10
+ input = input.dup
11
+ input.chomp!
12
+ if !input.strip.empty? # Ignore empty lines
13
+ @view.add_input(input)
14
+ end
15
+ end
16
+
17
+ end
18
+ end
@@ -0,0 +1,19 @@
1
+ module Repla::REPL
2
+ class OutputController < Repla::Controller
3
+
4
+ attr_accessor :view
5
+ def initialize(view)
6
+ @view = view
7
+ end
8
+
9
+ def parse_output(output)
10
+ output = output.dup
11
+ output.gsub!(/\x1b[^m]*m/, "") # Remove escape sequences
12
+ output.chomp!
13
+ if !output.strip.empty? # Ignore empty lines
14
+ @view.add_output(output)
15
+ end
16
+ end
17
+
18
+ end
19
+ end
@@ -0,0 +1,68 @@
1
+ module Repla::REPL
2
+ class View < Repla::View
3
+
4
+ BASE_DIRECTORY = File.join(File.dirname(__FILE__), "..")
5
+ VIEWS_DIRECTORY = File.join(BASE_DIRECTORY, "view")
6
+ VIEW_TEMPLATE = File.join(VIEWS_DIRECTORY, 'view.html.erb')
7
+ def initialize
8
+ super
9
+ self.base_url_path = File.expand_path(BASE_DIRECTORY)
10
+ load_erb_from_path(VIEW_TEMPLATE)
11
+ end
12
+
13
+ ADD_INPUT_JAVASCRIPT_FUNCTION = "WcREPL.addInput"
14
+ def add_input(input)
15
+ do_javascript_function(ADD_INPUT_JAVASCRIPT_FUNCTION, [input])
16
+ end
17
+
18
+ ADD_OUTPUT_JAVASCRIPT_FUNCTION = "WcREPL.addOutput"
19
+ def add_output(output)
20
+ do_javascript_function(ADD_OUTPUT_JAVASCRIPT_FUNCTION, [output])
21
+ end
22
+
23
+ # Helpers to allow easy loading of REPL resource even from another base URL
24
+
25
+ def repl_header_tags
26
+ %Q[
27
+ #{repl_stylesheet_link_tag}
28
+ #{repl_handlebars_template_tags}
29
+ #{shared_javascript_include_tag("handlebars")}
30
+ #{shared_javascript_include_tag("zepto")}
31
+ #{repl_javascript_include_tag}
32
+ ]
33
+ end
34
+
35
+ def repl_handlebars_template_tags
36
+ %Q[
37
+ <script id="output-template" type="text/x-handlebars-template">
38
+ <pre class="output"><code>{{code}}</code></pre>
39
+ </script>
40
+ <script id="input-template" type="text/x-handlebars-template">
41
+ <pre><code>{{code}}</code></pre>
42
+ </script>]
43
+ end
44
+
45
+ def repl_stylesheet_link_tag
46
+ path = File.join(repl_base_resource_path, "css/style.css")
47
+ url = repl_url_for_path(path)
48
+ stylesheet_link_tag(url)
49
+ end
50
+
51
+ def repl_javascript_include_tag
52
+ path = File.join(repl_base_resource_path, "js/wcrepl.js")
53
+ url = repl_url_for_path(path)
54
+ javascript_include_tag(url)
55
+ end
56
+
57
+ require 'open-uri'
58
+ def repl_url_for_path(path)
59
+ uri = URI::encode(path)
60
+ "file://" + uri
61
+ end
62
+
63
+ def repl_base_resource_path
64
+ File.expand_path(File.join(File.dirname(__FILE__), "../"))
65
+ end
66
+
67
+ end
68
+ end
@@ -0,0 +1,12 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <title><%= title %></title>
6
+ <%= shared_stylesheet_link_tag "raster" %>
7
+ <%= repl_header_tags %>
8
+ </head>
9
+ <body>
10
+
11
+ </body>
12
+ </html>
data/lib/repla/repl.rb ADDED
@@ -0,0 +1,49 @@
1
+ require_relative 'extension_constants'
2
+ require REPLA_FILE
3
+
4
+ module Repla::REPL
5
+ require_relative "repl/lib/input_controller"
6
+ require_relative "repl/lib/output_controller"
7
+ require_relative "repl/lib/view"
8
+
9
+ class Wrapper
10
+ require 'pty'
11
+
12
+ def initialize(command)
13
+
14
+ PTY.spawn(command) do |output, input, pid|
15
+ Thread.new do
16
+ output.each { |line|
17
+ output_controller.parse_output(line)
18
+ }
19
+ end
20
+ @input = input
21
+ end
22
+
23
+ end
24
+
25
+ def parse_input(input)
26
+ input_controller.parse_input(input)
27
+ write_input(input)
28
+ end
29
+
30
+ def write_input(input)
31
+ @input.write(input)
32
+ end
33
+
34
+ private
35
+
36
+ def input_controller
37
+ @input_controller ||= InputController.new(view)
38
+ end
39
+
40
+ def output_controller
41
+ @output_controller ||= OutputController.new(view)
42
+ end
43
+
44
+ def view
45
+ @view ||= View.new
46
+ end
47
+
48
+ end
49
+ end
data/lib/repla.rb ADDED
@@ -0,0 +1,9 @@
1
+ module Repla
2
+ require_relative "repla/lib/constants"
3
+ require_relative "repla/lib/window"
4
+ require_relative "repla/lib/controller"
5
+ require_relative "repla/lib/view"
6
+ require_relative "repla/lib/module"
7
+ end
8
+
9
+ Repla::application_exists || abort("The Web Console application is not installed.")
metadata ADDED
@@ -0,0 +1,92 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: repla
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.3.0
5
+ platform: ruby
6
+ authors:
7
+ - Roben Kleene
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-07-04 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: Bridge from Ruby to AppleScript to control Repla.
14
+ email: contact@robenkleene.com
15
+ executables: []
16
+ extensions: []
17
+ extra_rdoc_files: []
18
+ files:
19
+ - lib/applescript/close_window.scpt
20
+ - lib/applescript/create_window.scpt
21
+ - lib/applescript/do_javascript.scpt
22
+ - lib/applescript/exists.scpt
23
+ - lib/applescript/hide_log.scpt
24
+ - lib/applescript/load_html.scpt
25
+ - lib/applescript/load_html_with_base_url.scpt
26
+ - lib/applescript/load_plugin.scpt
27
+ - lib/applescript/read_from_standard_input.scpt
28
+ - lib/applescript/resource_path_for_plugin.scpt
29
+ - lib/applescript/resource_url_for_plugin.scpt
30
+ - lib/applescript/run_plugin.scpt
31
+ - lib/applescript/run_plugin_in_split.scpt
32
+ - lib/applescript/show_log.scpt
33
+ - lib/applescript/split_id_in_window.scpt
34
+ - lib/applescript/split_id_in_window_last.scpt
35
+ - lib/applescript/toggle_log.scpt
36
+ - lib/applescript/window_id_for_plugin.scpt
37
+ - lib/repla.rb
38
+ - lib/repla/dependencies.rb
39
+ - lib/repla/dependencies/css/style.css
40
+ - lib/repla/dependencies/js/wcdependencies.js
41
+ - lib/repla/dependencies/lib/controller.rb
42
+ - lib/repla/dependencies/lib/model.rb
43
+ - lib/repla/dependencies/lib/tester.rb
44
+ - lib/repla/dependencies/lib/view.rb
45
+ - lib/repla/dependencies/views/view.html.erb
46
+ - lib/repla/extension_constants.rb
47
+ - lib/repla/lib/constants.rb
48
+ - lib/repla/lib/controller.rb
49
+ - lib/repla/lib/module.rb
50
+ - lib/repla/lib/view.rb
51
+ - lib/repla/lib/view/erb.rb
52
+ - lib/repla/lib/view/javascript.rb
53
+ - lib/repla/lib/view/resources.rb
54
+ - lib/repla/lib/window.rb
55
+ - lib/repla/logger.rb
56
+ - lib/repla/logger/test/Rakefile
57
+ - lib/repla/logger/test/js/test_view_helper.js
58
+ - lib/repla/logger/test/lib/test_constants.rb
59
+ - lib/repla/logger/test/lib/test_view_helper.rb
60
+ - lib/repla/logger/test/run_tests.sh
61
+ - lib/repla/logger/test/tc_logger.rb
62
+ - lib/repla/repl.rb
63
+ - lib/repla/repl/css/style.css
64
+ - lib/repla/repl/js/wcrepl.js
65
+ - lib/repla/repl/lib/input_controller.rb
66
+ - lib/repla/repl/lib/output_controller.rb
67
+ - lib/repla/repl/lib/view.rb
68
+ - lib/repla/repl/view/view.html.erb
69
+ homepage:
70
+ licenses: []
71
+ metadata: {}
72
+ post_install_message:
73
+ rdoc_options: []
74
+ require_paths:
75
+ - lib
76
+ required_ruby_version: !ruby/object:Gem::Requirement
77
+ requirements:
78
+ - - "~>"
79
+ - !ruby/object:Gem::Version
80
+ version: '2.0'
81
+ required_rubygems_version: !ruby/object:Gem::Requirement
82
+ requirements:
83
+ - - ">="
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ requirements: []
87
+ rubyforge_project:
88
+ rubygems_version: 2.5.2.3
89
+ signing_key:
90
+ specification_version: 4
91
+ summary: Repla helper gem
92
+ test_files: []