blade 0.1.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,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 60c8ada090cd8f294eede5b5e0548cec699d2ad2
4
+ data.tar.gz: 505f81d5665a3251e61e48d725c5d14bd928aa31
5
+ SHA512:
6
+ metadata.gz: 5e9c1e879d5ed25c254ac83aeaf2855b3c36e68482555a4d54b3525f7d33f80191ba4d60993b80d09a0a4e1b2af2d0c70c6f31c611b088465b1107a103607c51
7
+ data.tar.gz: 8e37d85509f77ca11fb6eb859e01ba420541d00ce079114c3ef369c715f2568c6048fb1a0f7cb8cf8b79f0ff749d6a0863baad48857fe258e8b296c6761c65b7
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in blade.gemspec
4
+ gemspec
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2015 Javan Makhmali
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
13
+ all 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
21
+ THE SOFTWARE.
@@ -0,0 +1 @@
1
+ Blade: A [Sprockets](https://github.com/rails/sprockets) test runner and toolkit.
@@ -0,0 +1,12 @@
1
+ require "rake"
2
+ require "rake/testtask"
3
+ require "bundler/gem_tasks"
4
+
5
+ task default: :test
6
+
7
+ Rake::TestTask.new(:test) do |t|
8
+ t.libs << "test"
9
+ t.pattern = "test/*_test.rb"
10
+ t.verbose = true
11
+ end
12
+ Rake::Task[:test].comment = "Run tests"
@@ -0,0 +1,39 @@
1
+ getWebSocketURL = ->
2
+ element = document.querySelector("script[data-websocket]")
3
+ element.src.replace(/\/client\.js$/, "")
4
+
5
+ @client = new Faye.Client getWebSocketURL()
6
+ session_id = document.cookie.match(/blade_session=(\w+)/)?[1]
7
+
8
+ publish = ({channel, event, data}) ->
9
+ if session_id?
10
+ data = extend(copy(data), {event, session_id})
11
+ client.publish(channel, data)
12
+
13
+ copy = (object) ->
14
+ results = {}
15
+ results[key] = value for key, value of object
16
+ results
17
+
18
+ extend = (object, attributes) ->
19
+ object[key] = value for key, value of attributes
20
+ object
21
+
22
+ if session_id?
23
+ client.subscribe "/assets", (data) ->
24
+ location.reload() if data.changed
25
+
26
+ setInterval ->
27
+ publish(channel: "/browsers", event: "ping")
28
+ , 1000
29
+
30
+ @Blade =
31
+ suiteBegin: ({total}) ->
32
+ publish("/tests", event: "begin", data: {total})
33
+
34
+ testResult: ({name, pass, message}) ->
35
+ result = pass
36
+ publish(channel: "/tests", event: "result", data: {result, name, message})
37
+
38
+ suiteEnd: (details) ->
39
+ publish(channel: "/tests", event: "end", data: details)
@@ -0,0 +1,34 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <title>Blade Runner</title>
6
+ <script src="blade/websocket/client.js" data-websocket></script>
7
+
8
+ <% with_asset("index.js", :blade) do %>
9
+ <script src="blade.js"></script>
10
+ <% end %>
11
+
12
+ <%= render_asset("head.html", :user) %>
13
+
14
+ <% with_asset("index.css", :adapter) do %>
15
+ <link rel="stylesheet" type="text/css" href="blade/adapter.css">
16
+ <% end %>
17
+
18
+ <% with_asset("index.js", :adapter) do %>
19
+ <script src="blade/adapter.js"></script>
20
+ <% end %>
21
+
22
+ <%= render_asset("head.html", :adapter) %>
23
+
24
+ <% logical_paths(:js).each do |path| %>
25
+ <% with_asset(path, :user) do %>
26
+ <script src="<%= path %>"></script>
27
+ <% end %>
28
+ <% end %>
29
+ </head>
30
+ <body>
31
+ <%= render_asset("body.html", :user) %>
32
+ <%= render_asset("body.html", :adapter) %>
33
+ </body>
34
+ </html>
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "blade"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
@@ -0,0 +1,7 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+
5
+ bundle install
6
+
7
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,38 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'blade/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "blade"
8
+ spec.version = Blade::VERSION
9
+ spec.authors = ["Javan Makhmali"]
10
+ spec.email = ["javan@javan.us"]
11
+
12
+ spec.summary = %q{Blade}
13
+ spec.description = %q{Sprockets test runner and toolkit}
14
+ spec.homepage = "https://github.com/javan/blade"
15
+ spec.license = "MIT"
16
+
17
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
18
+ spec.bindir = "exe"
19
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
20
+ spec.require_paths = ["lib"]
21
+
22
+ spec.add_development_dependency "bundler", "~> 1.10"
23
+ spec.add_development_dependency "rake", "~> 10.0"
24
+
25
+ spec.add_dependency "blade-qunit_adapter"
26
+ spec.add_dependency "activesupport", ">= 3.0.0"
27
+ spec.add_dependency "coffee-script", "~> 2.4.0"
28
+ spec.add_dependency "coffee-script-source", "~> 1.9.0"
29
+ spec.add_dependency "curses", "~> 1.0.0"
30
+ spec.add_dependency "eventmachine", "~> 1.0.0"
31
+ # Lock to 1.1.1 to avoid Promise error in 1.1.2 with Chrome 43
32
+ # "Uncaught TypeError: Cannot read property '_state' of undefined"
33
+ spec.add_dependency "faye", "1.1.1"
34
+ spec.add_dependency "sprockets", "~> 3.2.0"
35
+ spec.add_dependency "thin", "~> 1.6.0"
36
+ spec.add_dependency "useragent", "~> 0.13.0"
37
+ spec.add_dependency "thor", "~> 0.19.1"
38
+ end
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "blade"
4
+
5
+ if ARGV.empty?
6
+ Blade::CLI.new.console
7
+ else
8
+ Blade.initialize!
9
+ Blade::CLI.start(ARGV)
10
+ end
@@ -0,0 +1,144 @@
1
+ require "active_support/all"
2
+ require "eventmachine"
3
+ require "faye"
4
+ require "pathname"
5
+ require "ostruct"
6
+ require "yaml"
7
+
8
+ require "blade/version"
9
+ require "blade/cli"
10
+
11
+ module Blade
12
+ extend self
13
+
14
+ @components = []
15
+
16
+ def register_component(component)
17
+ @components << component
18
+ end
19
+
20
+ require "blade/component"
21
+ require "blade/server"
22
+
23
+ autoload :Model, "blade/model"
24
+ autoload :Assets, "blade/assets"
25
+ autoload :RackAdapter, "blade/rack_adapter"
26
+ autoload :Session, "blade/session"
27
+ autoload :TestResults, "blade/test_results"
28
+ autoload :CombinedTestResults, "blade/combined_test_results"
29
+
30
+ extend Forwardable
31
+ def_delegators "Server.client", :subscribe, :publish
32
+
33
+ DEFAULT_FRAMEWORK = :qunit
34
+ DEFAULT_PORT = 9876
35
+
36
+ attr_reader :config, :plugins
37
+
38
+ def start(options = {})
39
+ return if running?
40
+ initialize!(options)
41
+ load_interface!
42
+
43
+ handle_exit
44
+
45
+ EM.run do
46
+ @components.each { |c| c.start if c.respond_to?(:start) }
47
+ @running = true
48
+ end
49
+ end
50
+
51
+ def stop
52
+ return if @stopping
53
+ @stopping = true
54
+ @components.each { |c| c.stop if c.respond_to?(:stop) }
55
+ EM.stop if EM.reactor_running?
56
+ @running = false
57
+ end
58
+
59
+ def running?
60
+ @running
61
+ end
62
+
63
+ def initialize!(options = {})
64
+ @options ||= {}.with_indifferent_access
65
+ @options.merge! options
66
+
67
+ setup_config!
68
+ load_plugins!
69
+ load_adapter!
70
+ end
71
+
72
+ def url(path = "")
73
+ "http://localhost:#{config.port}#{path}"
74
+ end
75
+
76
+ def root_path
77
+ Pathname.new(File.dirname(__FILE__)).join("../")
78
+ end
79
+
80
+ def tmp_path
81
+ Pathname.new(".").join("tmp/blade")
82
+ end
83
+
84
+ private
85
+ def handle_exit
86
+ %w( INT ).each do |signal|
87
+ trap(signal) { stop }
88
+ end
89
+
90
+ at_exit do
91
+ stop
92
+ exit $!.status if $!.is_a?(SystemExit)
93
+ end
94
+ end
95
+
96
+ def load_config_file!
97
+ filename = ".blade.yml"
98
+ if File.exists?(filename)
99
+ @options.reverse_merge!(YAML.load_file(filename))
100
+ end
101
+ end
102
+
103
+ def setup_config!
104
+ load_config_file!
105
+ options = @options.except(:plugins)
106
+
107
+ if options_for_interface = @options[options[:interface]]
108
+ options.merge! options_for_interface
109
+ end
110
+
111
+ options[:framework] ||= DEFAULT_FRAMEWORK
112
+ options[:port] ||= DEFAULT_PORT
113
+ options[:load_paths] = Array(options[:load_paths])
114
+ options[:logical_paths] = Array(options[:logical_paths])
115
+
116
+ @config = OpenStruct.new(options)
117
+
118
+ setup_plugin_config!
119
+ end
120
+
121
+ def setup_plugin_config!
122
+ @plugins = OpenStruct.new
123
+
124
+ plugin_options = @options[:plugins] || {}
125
+
126
+ plugin_options.each do |name, plugin_config|
127
+ plugins[name] = OpenStruct.new(config: OpenStruct.new(plugin_config))
128
+ end
129
+ end
130
+
131
+ def load_interface!
132
+ require "blade/interface/#{config.interface}"
133
+ end
134
+
135
+ def load_adapter!
136
+ require "blade/#{config.framework}_adapter"
137
+ end
138
+
139
+ def load_plugins!
140
+ plugins.to_h.keys.each do |name|
141
+ require "blade/#{name}_plugin"
142
+ end
143
+ end
144
+ end
@@ -0,0 +1,84 @@
1
+ require "sprockets"
2
+
3
+ module Blade::Assets
4
+ extend self
5
+
6
+ @environments = {}
7
+
8
+ def environment(name = :blade)
9
+ @environments[name] ||= Sprockets::Environment.new do |env|
10
+ env.cache = Sprockets::Cache::FileStore.new(Blade.tmp_path.join(name.to_s))
11
+
12
+ send("#{name}_load_paths").each do |path|
13
+ env.append_path(path)
14
+ end
15
+
16
+ env.context_class.class_eval do
17
+ extend Forwardable
18
+ def_delegators "Blade::Assets", :environment, :logical_paths
19
+
20
+ def with_asset(path, env_name)
21
+ if asset = environment(env_name)[path]
22
+ depend_on(asset.pathname)
23
+ yield(asset)
24
+ end
25
+ end
26
+
27
+ def render_asset(path, env_name)
28
+ with_asset(path, env_name) { |asset| asset.to_s }
29
+ end
30
+ end
31
+ end
32
+ end
33
+
34
+ def logical_paths(type = nil)
35
+ paths = Blade.config.logical_paths
36
+ paths.select! { |path| File.extname(path) == ".#{type}" } if type
37
+ paths
38
+ end
39
+
40
+ def blade_load_paths
41
+ [ Blade.root_path.join("assets") ]
42
+ end
43
+
44
+ def user_load_paths
45
+ Blade.config.load_paths.map { |a| Pathname.new(a) }
46
+ end
47
+
48
+ def adapter_load_paths
49
+ gem_name = "blade-#{Blade.config.framework}_adapter"
50
+ [ gem_pathname(gem_name).join("assets") ]
51
+ end
52
+
53
+ def watch_logical_paths
54
+ @mtimes = get_mtimes
55
+
56
+ EM.add_periodic_timer(1) do
57
+ mtimes = get_mtimes
58
+ unless mtimes == @mtimes
59
+ @mtimes = mtimes
60
+ Blade.publish("/assets", changed: @mtimes)
61
+ end
62
+ end
63
+ end
64
+
65
+ private
66
+ def get_mtimes
67
+ {}.tap do |mtimes|
68
+ Blade.config.logical_paths.each do |path|
69
+ mtimes[path] = get_mtime(path)
70
+ end
71
+ end
72
+ end
73
+
74
+ def get_mtime(logical_path)
75
+ environment_for(:user)[logical_path].mtime
76
+ rescue Exception => e
77
+ e.to_s
78
+ end
79
+
80
+ def gem_pathname(gem_name)
81
+ gemspec = Gem::Specification.find_by_name(gem_name)
82
+ Pathname.new(gemspec.gem_dir)
83
+ end
84
+ end
@@ -0,0 +1,13 @@
1
+ require "thor"
2
+
3
+ class Blade::CLI < Thor
4
+ desc "console", "Start in console mode"
5
+ def console
6
+ Blade.start(interface: :console)
7
+ end
8
+
9
+ desc "ci", "Start in CI mode"
10
+ def ci
11
+ Blade.start(interface: :ci)
12
+ end
13
+ end