pax_global_header 0000666 0000000 0000000 00000000064 14225317050 0014511 g ustar 00root root 0000000 0000000 52 comment=fb37a85a81689afab25627b312ca0d42e8bd32ca
blade-0.7.3/ 0000775 0000000 0000000 00000000000 14225317050 0012567 5 ustar 00root root 0000000 0000000 blade-0.7.3/.gitignore 0000664 0000000 0000000 00000000127 14225317050 0014557 0 ustar 00root root 0000000 0000000 /.bundle/
/.yardoc
/Gemfile.lock
/_yardoc/
/coverage/
/doc/
/pkg/
/spec/reports/
/tmp/
blade-0.7.3/Gemfile 0000664 0000000 0000000 00000000132 14225317050 0014056 0 ustar 00root root 0000000 0000000 source 'https://rubygems.org'
# Specify your gem's dependencies in blade.gemspec
gemspec
blade-0.7.3/LICENSE.txt 0000664 0000000 0000000 00000002071 14225317050 0014412 0 ustar 00root root 0000000 0000000 The MIT License (MIT)
Copyright (c) 2016 Javan Makhmali
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
blade-0.7.3/README.md 0000664 0000000 0000000 00000004010 14225317050 0014041 0 ustar 00root root 0000000 0000000 # Blade
### A [Sprockets](https://github.com/rails/sprockets) Toolkit for Building and Testing JavaScript Libraries
## Getting Started
Add Blade to your `Gemfile`.
```ruby
source "https://rubygems.org"
gem 'blade'
```
Create a `.blade.yml` (or `blade.yml`) file in your project’s root, and define your Sprockets [load paths](https://github.com/rails/sprockets#the-load-path) and [logical paths](https://github.com/rails/sprockets#logical-paths). Example:
```yaml
# .blade.yml
load_paths:
- src
- test/src
- test/vendor
logical_paths:
- widget.js
- test.js
```
## Compiling
Configure your build paths and [compressors](https://github.com/rails/sprockets#minifying-assets):
```yaml
# .blade.yml
…
build:
logical_paths:
- widget.js
path: dist
js_compressor: uglifier # Optional
```
Run `bundle exec blade build` to compile `dist/widget.js`.
## Testing Locally
By default, Blade sets up a test runner using [QUnit](http://qunitjs.com/) via the [blade-qunit_adapter](https://github.com/javan/blade-qunit_adapter) gem.
Run `bundle exec blade runner` to launch Blade’s test console and open the URL it displays in one or more browsers. Blade detects changes to your logical paths and automatically restarts the test suite.

## Testing on CI
Run `bundle exec blade ci` to start Blade’s test console in non-interactive CI mode, and launch a browser pointed at Blade’s testing URL (usually http://localhost:9876). The process will return `0` on success and non-zero on failure.
To test on multiple browsers with [Sauce Labs](https://saucelabs.com/), see the [Sauce Labs plugin](https://github.com/javan/blade-sauce_labs_plugin).
## Projects Using Blade
* [Trix](https://github.com/basecamp/trix)
* [Turbolinks](https://github.com/turbolinks/turbolinks)
* [Action Cable](https://github.com/rails/rails/tree/master/actioncable)
---
Licensed under the [MIT License](LICENSE.txt)
© 2016 Javan Makhmali
blade-0.7.3/Rakefile 0000664 0000000 0000000 00000000353 14225317050 0014235 0 ustar 00root root 0000000 0000000 require "rake"
require "rake/testtask"
require "bundler/gem_tasks"
task default: :test
Rake::TestTask.new(:test) do |t|
t.libs << "test"
t.pattern = "test/*_test.rb"
t.verbose = true
end
Rake::Task[:test].comment = "Run tests"
blade-0.7.3/assets/ 0000775 0000000 0000000 00000000000 14225317050 0014071 5 ustar 00root root 0000000 0000000 blade-0.7.3/assets/blade/ 0000775 0000000 0000000 00000000000 14225317050 0015140 5 ustar 00root root 0000000 0000000 blade-0.7.3/assets/blade/index.coffee 0000664 0000000 0000000 00000001733 14225317050 0017424 0 ustar 00root root 0000000 0000000 @Blade =
suiteDidBegin: ({total}) ->
event = "begin"
publish("/tests", {event, total})
testDidEnd: ({name, status, message}) ->
event = "result"
publish("/tests", {event, name, status, message})
suiteDidEnd: ({total}) ->
event = "end"
publish("/tests", {event, total})
publish = (channel, data = {}) ->
client.publish(channel, copy(data, {session_id})) if session_id?
copy = (object, withAttributes = {}) ->
result = {}
result[key] = value for key, value of object
result[key] = value for key, value of withAttributes
result
getWebSocketURL = ->
element = document.querySelector("script[data-websocket]")
element.src.replace(/\/client\.js$/, "")
getSessionId = ->
document.cookie.match(/blade_session=(\w+)/)?[1]
client = new Faye.Client(getWebSocketURL())
if session_id = getSessionId()
client.subscribe "/assets", (data) ->
location.reload() if data.changed
setInterval ->
publish("/browsers", event: "ping")
, 1000
blade-0.7.3/assets/blade/index.html.erb 0000664 0000000 0000000 00000001521 14225317050 0017703 0 ustar 00root root 0000000 0000000
Blade Runner
<% if environment["head.html"] %>
<%= depend_on_asset("head.html").to_s %>
<% end %>
<% if environment["adapter/head.html"] %>
<%= depend_on_asset("blade/adapter/head.html").to_s %>
<% end %>
<% logical_paths(:js).each do |path| %>
<% end %>
<% if environment["body.html"] %>
<%= depend_on_asset("body.html").to_s %>
<% end %>
<% if environment["blade/adapter/body.html"] %>
<%= depend_on_asset("blade/adapter/body.html").to_s %>
<% end %>
blade-0.7.3/bin/ 0000775 0000000 0000000 00000000000 14225317050 0013337 5 ustar 00root root 0000000 0000000 blade-0.7.3/bin/console 0000775 0000000 0000000 00000000512 14225317050 0014725 0 ustar 00root root 0000000 0000000 #!/usr/bin/env ruby
require "bundler/setup"
require "blade"
# You can add fixtures and/or initialization code here to make experimenting
# with your gem easier. You can also use a different console, if you like.
# (If you use this, don't forget to add pry to your Gemfile!)
# require "pry"
# Pry.start
require "irb"
IRB.start
blade-0.7.3/bin/rake 0000775 0000000 0000000 00000000554 14225317050 0014213 0 ustar 00root root 0000000 0000000 #!/usr/bin/env ruby
#
# This file was generated by Bundler.
#
# The application 'rake' is installed as part of a gem, and
# this file is here to facilitate running it.
#
require "pathname"
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
Pathname.new(__FILE__).realpath)
require "rubygems"
require "bundler/setup"
load Gem.bin_path("rake", "rake")
blade-0.7.3/bin/setup 0000775 0000000 0000000 00000000163 14225317050 0014425 0 ustar 00root root 0000000 0000000 #!/bin/bash
set -euo pipefail
IFS=$'\n\t'
bundle install
# Do any other automated setup that you need to do here
blade-0.7.3/blade.gemspec 0000664 0000000 0000000 00000002463 14225317050 0015210 0 ustar 00root root 0000000 0000000 # coding: utf-8
lib = File.expand_path('../lib', __FILE__)
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
require 'blade/version'
Gem::Specification.new do |spec|
spec.name = "blade"
spec.version = Blade::VERSION
spec.authors = ["Javan Makhmali"]
spec.email = ["javan@javan.us"]
spec.summary = %q{Blade}
spec.description = %q{Sprockets test runner and toolkit}
spec.homepage = "https://github.com/javan/blade"
spec.license = "MIT"
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
spec.bindir = "exe"
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
spec.require_paths = ["lib"]
spec.add_development_dependency "bundler", ">= 2.0"
spec.add_development_dependency "rake", ">= 10.0"
spec.add_dependency "blade-qunit_adapter", ">= 2.0.1"
spec.add_dependency "activesupport", ">= 3.0.0"
spec.add_dependency "coffee-script"
spec.add_dependency "coffee-script-source"
spec.add_dependency "curses", ">= 1.4.0"
spec.add_dependency "eventmachine"
spec.add_dependency "faye"
spec.add_dependency "sprockets", ">= 3.0"
spec.add_dependency "thin", ">= 1.6.0"
spec.add_dependency "useragent", ">= 0.16.7"
spec.add_dependency "thor", ">= 0.19.1"
end
blade-0.7.3/exe/ 0000775 0000000 0000000 00000000000 14225317050 0013350 5 ustar 00root root 0000000 0000000 blade-0.7.3/exe/blade 0000775 0000000 0000000 00000000074 14225317050 0014346 0 ustar 00root root 0000000 0000000 #!/usr/bin/env ruby
require "blade"
Blade::CLI.start(ARGV)
blade-0.7.3/lib/ 0000775 0000000 0000000 00000000000 14225317050 0013335 5 ustar 00root root 0000000 0000000 blade-0.7.3/lib/blade.rb 0000664 0000000 0000000 00000005540 14225317050 0014735 0 ustar 00root root 0000000 0000000 require "active_support/all"
require "eventmachine"
require "faye"
require "pathname"
require "yaml"
require "blade/version"
require "blade/cli"
module Blade
extend self
CONFIG_DEFAULTS = {
framework: :qunit,
port: 9876,
build: { path: "." }
}
CONFIG_FILENAMES = %w( blade.yml .blade.yml )
@components = []
def register_component(component)
@components << component
end
require "blade/component"
require "blade/server"
autoload :Model, "blade/model"
autoload :Assets, "blade/assets"
autoload :Config, "blade/config"
autoload :RackAdapter, "blade/rack/adapter"
autoload :RackRouter, "blade/rack/router"
autoload :Session, "blade/session"
autoload :TestResults, "blade/test_results"
delegate :subscribe, :publish, to: Server
attr_reader :config
def start(options = {})
return if running?
ensure_tmp_path
initialize!(options)
load_interface
handle_exit
EM.run do
@components.each { |c| c.try(:start) }
@running = true
end
end
def stop
return if @stopping
@stopping = true
@components.each { |c| c.try(:stop) }
EM.stop if EM.reactor_running?
@running = false
end
def running?
@running
end
def initialize!(options = {})
return if @initialized
@initialized = true
options = CONFIG_DEFAULTS.deep_merge(blade_file_options).deep_merge(options)
@config = Blade::Config.new options
config.load_paths = Array(config.load_paths)
config.logical_paths = Array(config.logical_paths)
if config.build?
config.build.logical_paths = Array(config.build.logical_paths)
config.build.path ||= "."
end
config.plugins ||= {}
load_requires
load_plugins
load_adapter
end
def build
initialize!
Assets.build
end
def url(path = "/")
"http://#{Server.host}:#{config.port}#{path}"
end
def root_path
Pathname.new(File.dirname(__FILE__)).join("../")
end
def tmp_path
Pathname.new(".").join("tmp/blade")
end
def ensure_tmp_path
tmp_path.mkpath
end
def clean_tmp_path
tmp_path.rmtree if tmp_path.exist?
end
private
def handle_exit
at_exit do
stop
exit $!.status if $!.is_a?(SystemExit)
end
%w( INT ).each do |signal|
trap(signal) { exit(1) }
end
end
def blade_file_options
if filename = CONFIG_FILENAMES.detect { |name| File.exist?(name) }
YAML.load_file(filename)
else
{}
end
end
def load_interface
require "blade/interface/#{config.interface}"
end
def load_adapter
require "blade/#{config.framework}_adapter"
end
def load_requires
Array(config.require).each do |path|
require path
end
end
def load_plugins
config.plugins.keys.each do |name|
require "blade/#{name}_plugin"
end
end
end
blade-0.7.3/lib/blade/ 0000775 0000000 0000000 00000000000 14225317050 0014404 5 ustar 00root root 0000000 0000000 blade-0.7.3/lib/blade/assets.rb 0000664 0000000 0000000 00000003622 14225317050 0016236 0 ustar 00root root 0000000 0000000 require "sprockets"
module Blade::Assets
autoload :Builder, "blade/assets/builder"
extend self
def environment
@environment ||= Sprockets::Environment.new do |env|
env.cache = Sprockets::Cache::FileStore.new(Blade.tmp_path)
%w( blade user adapter ).each do |name|
send("#{name}_load_paths").each do |path|
env.append_path(path)
end
end
env.context_class.class_eval do
delegate :logical_paths, to: Blade::Assets
end
end
end
def build
if Blade.config.build
Builder.new(environment).build
end
end
def logical_paths(type = nil)
paths = Blade.config.logical_paths
paths.select! { |path| File.extname(path) == ".#{type}" } if type
paths
end
def blade_load_paths
[ Blade.root_path.join("assets") ]
end
def user_load_paths
Blade.config.load_paths.flat_map do |load_path|
if load_path.is_a?(Hash)
load_path.flat_map do |gem_name, paths|
Array(paths).map{ |path| gem_pathname(gem_name).join(path) }
end
else
Pathname.new(load_path)
end
end
end
def adapter_load_paths
gem_name = "blade-#{Blade.config.framework}_adapter"
[ gem_pathname(gem_name).join("assets") ]
end
def watch_logical_paths
@mtimes = get_mtimes
EM.add_periodic_timer(1) do
mtimes = get_mtimes
unless mtimes == @mtimes
@mtimes = mtimes
Blade.publish("/assets", changed: @mtimes)
end
end
end
private
def get_mtimes
{}.tap do |mtimes|
Blade.config.logical_paths.each do |path|
mtimes[path] = get_mtime(path)
end
end
end
def get_mtime(logical_path)
environment[logical_path].mtime
rescue Exception => e
e.to_s
end
def gem_pathname(gem_name)
gemspec = Gem::Specification.find_by_name(gem_name)
Pathname.new(gemspec.gem_dir)
end
end
blade-0.7.3/lib/blade/assets/ 0000775 0000000 0000000 00000000000 14225317050 0015706 5 ustar 00root root 0000000 0000000 blade-0.7.3/lib/blade/assets/builder.rb 0000664 0000000 0000000 00000003171 14225317050 0017663 0 ustar 00root root 0000000 0000000 class Blade::Assets::Builder
attr_accessor :environment
def initialize(environment)
@environment = environment
end
def build
puts "Building assets…"
clean
compile
clean_dist_path
create_dist_path
install
end
private
def compile
environment.js_compressor = Blade.config.build.js_compressor.try(:to_sym)
environment.css_compressor = Blade.config.build.css_compressor.try(:to_sym)
manifest.compile(logical_paths)
end
def install
logical_paths.each do |logical_path|
fingerprint_path = manifest.assets[logical_path]
source_path = compile_path.join(fingerprint_path)
destination_path = dist_path.join(logical_path)
FileUtils.cp(source_path, destination_path)
puts "[created] #{destination_path}"
end
end
def manifest
@manifest ||= Sprockets::Manifest.new(environment.index, compile_path)
end
def clean
compile_path.rmtree if compile_path.exist?
compile_path.mkpath
end
def logical_paths
Blade.config.build.logical_paths
end
def create_dist_path
dist_path.mkpath unless dist_path.exist?
end
def clean_dist_path
if clean_dist_path?
children = dist_path.children
dist_path.rmtree
children.each do |child|
puts "[removed] #{child}"
end
end
end
def clean_dist_path?
Blade.config.build.clean && dist_path.exist?
end
def dist_path
@dist_path ||= Pathname.new(Blade.config.build.path)
end
def compile_path
@compile_path ||= Blade.tmp_path.join("compile")
end
end
blade-0.7.3/lib/blade/cli.rb 0000664 0000000 0000000 00000000655 14225317050 0015506 0 ustar 00root root 0000000 0000000 require "thor"
class Blade::CLI < Thor
desc "runner", "Start test runner in console mode"
def runner
Blade.start(interface: :runner)
end
desc "ci", "Start test runner in CI mode"
def ci
Blade.start(interface: :ci)
end
desc "build", "Build assets"
def build
Blade.build
end
desc "config", "Inspect Blade.config"
def config
require "pp"
Blade.initialize!
pp Blade.config
end
end
blade-0.7.3/lib/blade/component.rb 0000664 0000000 0000000 00000000137 14225317050 0016734 0 ustar 00root root 0000000 0000000 module Blade::Component
def self.included(base)
Blade.register_component(base)
end
end
blade-0.7.3/lib/blade/config.rb 0000664 0000000 0000000 00000000565 14225317050 0016204 0 ustar 00root root 0000000 0000000 class Blade::Config < ActiveSupport::HashWithIndifferentAccess
def method_missing(method, *args)
case method
when /=$/
self[$`] = args.first
when /\?$/
self[$`].present?
else
if self[method].is_a?(Hash) && !self[method].is_a?(self.class)
self[method] = self.class.new(self[method])
end
self[method]
end
end
end
blade-0.7.3/lib/blade/interface/ 0000775 0000000 0000000 00000000000 14225317050 0016344 5 ustar 00root root 0000000 0000000 blade-0.7.3/lib/blade/interface/ci.rb 0000664 0000000 0000000 00000002237 14225317050 0017270 0 ustar 00root root 0000000 0000000 module Blade::CI
extend self
include Blade::Component
def start
@completed_sessions = 0
@failures = []
Blade.subscribe("/results") do |details|
process_result(details)
end
end
private
def process_result(details)
if status = details[:status]
STDOUT.print status_dot(status)
if status == "fail"
@failures << details
end
end
if details[:completed]
process_completion
end
end
def process_completion
@completed_sessions += 1
if done?
EM.add_timer 2 do
display_failures
STDOUT.puts
exit_with_status_code
end
end
end
def status_dot(status)
Blade::TestResults::STATUS_DOTS[status]
end
def done?
@completed_sessions == (Blade.config.expected_sessions || 1)
end
def display_failures
@failures.each do |details|
STDERR.puts "\n\n#{status_dot(details[:status])} #{details[:name]} (#{Blade::Session.find(details[:session_id])})"
STDERR.puts details[:message]
end
end
def exit_with_status_code
exit @failures.any? ? 1 : 0
end
end
blade-0.7.3/lib/blade/interface/runner.rb 0000664 0000000 0000000 00000005031 14225317050 0020201 0 ustar 00root root 0000000 0000000 require "curses"
module Blade::Runner
extend self
include Blade::Component
autoload :Tab, "blade/interface/runner/tab"
COLOR_NAMES = %w( white yellow green red )
PADDING = 1
def colors
@colors ||= OpenStruct.new.tap do |colors|
COLOR_NAMES.each do |name|
const = Curses.const_get("COLOR_#{name.upcase}")
Curses.init_pair(const, const, Curses::COLOR_BLACK)
colors[name] = Curses.color_pair(const)
end
end
end
def create_window(options = {})
height = options[:height] || 0
width = options[:width] || 0
top = options[:top] || 0
left = options[:left] || PADDING
parent = options[:parent] || Curses.stdscr
parent.subwin(height, width, top, left)
end
def start
run
Blade::Assets.watch_logical_paths
end
def stop
Curses.close_screen
end
def run
start_screen
init_windows
handle_keys
handle_stale_tabs
Blade.subscribe("/results") do |details|
session = Blade::Session.find(details[:session_id])
unless tab = Tab.find(session.id)
tab = Tab.create(id: session.id)
tab.activate if Tab.size == 1
end
tab.draw
Curses.doupdate
end
end
private
def start_screen
Curses.init_screen
Curses.start_color
Curses.noecho
Curses.curs_set(0)
Curses.stdscr.keypad(true)
end
def init_windows
header_window = create_window(height: 3)
header_window.attron(Curses::A_BOLD)
header_window.addstr "BLADE RUNNER [press 'q' to quit]\n"
header_window.attroff(Curses::A_BOLD)
header_window.addstr "Open #{Blade.url} to start"
header_window.noutrefresh
Tab.install(top: header_window.maxy)
Curses.doupdate
end
def handle_keys
EM.defer do
while ch = Curses.getch
case ch
when Curses::KEY_LEFT
Tab.active.try(:activate_previous)
Curses.doupdate
when Curses::KEY_RIGHT
Tab.active.try(:activate_next)
Curses.doupdate
when "q"
Blade.stop
end
end
end
end
def handle_stale_tabs
Blade.subscribe("/browsers") do |details|
if details["message"] = "ping"
if tab = Tab.find(details["session_id"])
tab.last_ping_at = Time.now
end
end
end
EM.add_periodic_timer(1) do
Tab.stale.each { |t| remove_tab(t) }
end
end
def remove_tab(tab)
Tab.remove(tab.id)
Curses.doupdate
end
end
blade-0.7.3/lib/blade/interface/runner/ 0000775 0000000 0000000 00000000000 14225317050 0017655 5 ustar 00root root 0000000 0000000 blade-0.7.3/lib/blade/interface/runner/tab.rb 0000664 0000000 0000000 00000007135 14225317050 0020756 0 ustar 00root root 0000000 0000000 class Blade::Runner::Tab < Blade::Model
delegate :colors, :create_window, to: Blade::Runner
class << self
delegate :create_window, to: Blade::Runner
attr_reader :window, :state_window, :content_window
def install(options = {})
top = options[:top]
@window = create_window(top: top, height: 3)
top = @window.begy + @window.maxy + 1
@state_window = create_window(top: top, height: 1)
top = @state_window.begy + @state_window.maxy + 1
@content_window = create_window(top: top)
@content_window.scrollok(true)
end
def draw
window.clear
window.noutrefresh
all.each(&:draw)
end
def remove(id)
tab = find(id)
tab.deactivate
tab.window.close
super
draw
end
def active
all.detect(&:active?)
end
def stale
threshold = Time.now - 2
all.select { |t| t.last_ping_at && t.last_ping_at < threshold }
end
end
def tabs
self.class
end
def height
3
end
def width
5
end
def top
tabs.window.begy
end
def left
tabs.window.begx + index * width
end
def window
@window ||= create_window(height: height, width: width, top: top, left: left)
end
def draw
window.clear
active? ? draw_active : draw_inactive
window.noutrefresh
end
def draw_active
window.addstr "╔═══╗"
window.addstr "║ "
window.attron(color)
window.addstr(dot)
window.attroff(color)
window.addstr(" ║")
window.addstr "╝ ╚"
draw_test_results
end
def draw_inactive
window.addstr "\n"
window.attron(color)
window.addstr(" #{dot}\n")
window.attroff(color)
window.addstr "═════"
end
def draw_test_results
tabs.content_window.clear
failures = []
session.test_results.results.each do |result|
tabs.content_window.addstr(status_dot(result))
failures << result if result[:status] == "fail"
end
failures.each do |result|
tabs.content_window.addstr("\n\n")
tabs.content_window.attron(Curses::A_BOLD)
tabs.content_window.attron(colors.red)
tabs.content_window.addstr("#{status_dot(result)} #{result[:name]}\n")
tabs.content_window.attroff(colors.red)
tabs.content_window.attroff(Curses::A_BOLD)
tabs.content_window.addstr(result[:message])
end
tabs.content_window.noutrefresh
end
def dot
state == "pending" ? "○" : "●"
end
def status_dot(result)
Blade::TestResults::STATUS_DOTS[result[:status]]
end
def index
tabs.all.index(self)
end
def session
Blade::Session.find(id)
end
def state
session.test_results.state
end
def active?
active
end
def activate
return if active?
if tab = tabs.active
tab.deactivate
end
self.active = true
draw
tabs.state_window.addstr(session.to_s)
tabs.state_window.noutrefresh
end
def deactivate
return unless active?
self.active = false
draw
tabs.state_window.clear
tabs.state_window.noutrefresh
tabs.content_window.clear
tabs.content_window.noutrefresh
end
def activate_next
all = tabs.all
if all.last == self
all.first.activate
elsif tab = all[index + 1]
tab.activate
end
end
def activate_previous
all = tabs.all
if all.first == self
all.last.activate
elsif tab = all[index - 1]
tab.activate
end
end
def color
case state
when "running" then colors.yellow
when "finished" then colors.green
when /fail/ then colors.red
else colors.white
end
end
end
blade-0.7.3/lib/blade/model.rb 0000664 0000000 0000000 00000000675 14225317050 0016041 0 ustar 00root root 0000000 0000000 require "securerandom"
class Blade::Model < OpenStruct
class << self
def models
@models ||= {}
end
def create(attributes)
attributes[:id] ||= SecureRandom.hex(4)
model = new(attributes)
models[model.id] = model
end
def find(id)
models[id]
end
def remove(id)
models.delete(id)
end
def all
models.values
end
def size
models.size
end
end
end
blade-0.7.3/lib/blade/rack/ 0000775 0000000 0000000 00000000000 14225317050 0015324 5 ustar 00root root 0000000 0000000 blade-0.7.3/lib/blade/rack/adapter.rb 0000664 0000000 0000000 00000003326 14225317050 0017275 0 ustar 00root root 0000000 0000000 class Blade::RackAdapter
include Blade::RackRouter
route "", to: :redirect_to_index
route "/", to: :index
route "/blade/websocket*", to: :websocket
default_route to: :environment
attr_reader :request, :env
def initialize
Blade.initialize!
end
def call(env)
@env = env
@request = Rack::Request.new(env)
route = find_route(request.path_info)
base_path, action = route.values_at(:base_path, :action)
rewrite_path!(base_path)
send(action[:to])
end
def index
request.path_info = "/blade/index.html"
response = environment
response = add_session_cookie(response) if needs_session_cookie?
response.to_a
end
def redirect_to_index
Rack::Response.new.tap do |response|
path = request.path
path = path + "/" unless path.last == "/"
response.redirect(path)
end.to_a
end
def websocket
faye_adapter.call(env)
end
def environment
Blade::Assets.environment.call(env)
end
private
def needs_session_cookie?
Blade.running? && !Blade::Session.find(request.cookies[Blade::Session::KEY])
end
def add_session_cookie(response)
user_agent = UserAgent.parse(request.user_agent)
session = Blade::Session.create(user_agent: user_agent)
status, headers, body = response
response = Rack::Response.new(body, status, headers)
response.set_cookie(Blade::Session::KEY, session.id)
response
end
def rewrite_path!(path = nil)
return if path.nil?
request.path_info = request.path_info.sub(path, "").presence || "/"
request.script_name = request.script_name + path
end
def faye_adapter
@faye_adapter ||= Faye::RackAdapter.new(mount: "/", timeout: 25)
end
end
blade-0.7.3/lib/blade/rack/router.rb 0000664 0000000 0000000 00000001436 14225317050 0017175 0 ustar 00root root 0000000 0000000 module Blade::RackRouter
extend ActiveSupport::Concern
DEFAULT = :*
included do
cattr_accessor(:routes) { Hash.new }
end
class_methods do
def route(path, action)
pattern = /^\/?#{path.gsub(/\*/, ".*")}$/
base_path = path.match(/([^\*]*)\*?/)[1]
routes[path] = { action: action, pattern: pattern, base_path: base_path }
self.routes = routes.sort_by { |path, value| -path.size }.to_h
routes[path]
end
def default_route(action)
routes[DEFAULT] = { action: action }
end
def find_route(path)
if route = routes.detect { |key, details| path =~ details[:pattern] }
route[1]
else
routes[DEFAULT]
end
end
end
private
def find_route(*args)
self.class.find_route(*args)
end
end
blade-0.7.3/lib/blade/server.rb 0000664 0000000 0000000 00000001513 14225317050 0016237 0 ustar 00root root 0000000 0000000 require "faye/websocket"
require "useragent"
module Blade::Server
extend self
include Blade::Component
WEBSOCKET_PATH = "/blade/websocket"
def start
Faye::WebSocket.load_adapter("thin")
Thin::Logging.silent = true
Thin::Server.start(host, Blade.config.port, app, signals: false)
end
def host
Thin::Server::DEFAULT_HOST
end
def websocket_url(path = "")
Blade.url(WEBSOCKET_PATH + path)
end
def client
@client ||= Faye::Client.new(websocket_url)
end
def subscribe(channel)
client.subscribe(channel) do |message|
yield message.with_indifferent_access
end
end
def publish(channel, message)
client.publish(channel, message)
end
private
def app
Rack::Builder.app do
use Rack::ShowExceptions
run Blade::RackAdapter.new
end
end
end
blade-0.7.3/lib/blade/session.rb 0000664 0000000 0000000 00000000643 14225317050 0016417 0 ustar 00root root 0000000 0000000 class Blade::Session < Blade::Model
KEY = "blade_session"
class << self
def create(attributes)
model = super
model.test_results = Blade::TestResults.new(model.id)
model
end
def combined_test_results
Blade::CombinedTestResults.new(all)
end
end
def to_s
@to_s ||= "#{ua.browser} #{ua.version} #{ua.platform}"
end
private
def ua
user_agent
end
end
blade-0.7.3/lib/blade/test_results.rb 0000664 0000000 0000000 00000002106 14225317050 0017470 0 ustar 00root root 0000000 0000000 class Blade::TestResults
STATUS_DOTS = { pass: ".", fail: "✗" }.with_indifferent_access
attr_reader :session_id, :state, :results, :total, :failures
def initialize(session_id)
@session_id = session_id
reset
Blade.subscribe("/tests") do |details|
if details[:session_id] == session_id
event = details.delete(:event)
try("process_#{event}", details)
end
end
end
def reset
@results = []
@state = "pending"
@total = 0
@failures = 0
end
def process_begin(details)
reset
@state = "running"
@total = details[:total]
publish(total: @total)
end
def process_result(details)
result = details.slice(:status, :name, :message)
@results << result
if result[:status] == "fail"
@state = "failing"
@failures += 1
end
publish(result)
end
def process_end(details)
@state = failures.zero? ? "finished" : "failed"
publish(completed: true)
end
def publish(message = {})
Blade.publish("/results", message.merge(state: state, session_id: session_id))
end
end
blade-0.7.3/lib/blade/version.rb 0000664 0000000 0000000 00000000045 14225317050 0016415 0 ustar 00root root 0000000 0000000 module Blade
VERSION = "0.7.3"
end
blade-0.7.3/test/ 0000775 0000000 0000000 00000000000 14225317050 0013546 5 ustar 00root root 0000000 0000000 blade-0.7.3/test/blade_test.rb 0000664 0000000 0000000 00000000167 14225317050 0016205 0 ustar 00root root 0000000 0000000 require "test_helper"
class BladeTest < Blade::TestCase
test "initialize" do
assert Blade.initialize!
end
end
blade-0.7.3/test/test_helper.rb 0000664 0000000 0000000 00000000204 14225317050 0016405 0 ustar 00root root 0000000 0000000 require "blade"
require "minitest/autorun"
ActiveSupport.test_order = :random
class Blade::TestCase < ActiveSupport::TestCase
end