shoes-core 4.0.0.pre3
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 +7 -0
- data/LICENSE +31 -0
- data/README.md +8 -0
- data/Rakefile +1 -0
- data/bin/shoes +62 -0
- data/bin/shoes-guard +8 -0
- data/bin/shoes-picker +6 -0
- data/bin/shoes-stub +62 -0
- data/ext/install/Rakefile +29 -0
- data/ext/install/shoes.bat +15 -0
- data/fonts/Coolvetica.ttf +0 -0
- data/fonts/Lacuna.ttf +0 -0
- data/lib/rubygems_plugin.rb +24 -0
- data/lib/shoes.rb +1 -0
- data/lib/shoes/animation.rb +56 -0
- data/lib/shoes/app.rb +130 -0
- data/lib/shoes/arc.rb +25 -0
- data/lib/shoes/background.rb +20 -0
- data/lib/shoes/border.rb +20 -0
- data/lib/shoes/builtin_methods.rb +76 -0
- data/lib/shoes/button.rb +29 -0
- data/lib/shoes/check_button.rb +41 -0
- data/lib/shoes/color.rb +387 -0
- data/lib/shoes/common/background_element.rb +9 -0
- data/lib/shoes/common/changeable.rb +34 -0
- data/lib/shoes/common/clickable.rb +24 -0
- data/lib/shoes/common/inspect.rb +14 -0
- data/lib/shoes/common/positioning.rb +30 -0
- data/lib/shoes/common/registration.rb +31 -0
- data/lib/shoes/common/remove.rb +10 -0
- data/lib/shoes/common/state.rb +16 -0
- data/lib/shoes/common/style.rb +160 -0
- data/lib/shoes/common/style_normalizer.rb +16 -0
- data/lib/shoes/common/ui_element.rb +11 -0
- data/lib/shoes/common/visibility.rb +41 -0
- data/lib/shoes/configuration.rb +96 -0
- data/lib/shoes/core.rb +1 -0
- data/lib/shoes/core/version.rb +5 -0
- data/lib/shoes/dialog.rb +56 -0
- data/lib/shoes/dimension.rb +269 -0
- data/lib/shoes/dimensions.rb +203 -0
- data/lib/shoes/download.rb +130 -0
- data/lib/shoes/dsl.rb +656 -0
- data/lib/shoes/file_not_found_error.rb +4 -0
- data/lib/shoes/font.rb +50 -0
- data/lib/shoes/gradient.rb +31 -0
- data/lib/shoes/image.rb +53 -0
- data/lib/shoes/image_pattern.rb +12 -0
- data/lib/shoes/input_box.rb +59 -0
- data/lib/shoes/internal_app.rb +230 -0
- data/lib/shoes/key_event.rb +17 -0
- data/lib/shoes/line.rb +84 -0
- data/lib/shoes/link.rb +57 -0
- data/lib/shoes/link_hover.rb +5 -0
- data/lib/shoes/list_box.rb +50 -0
- data/lib/shoes/logger.rb +65 -0
- data/lib/shoes/logger/ruby.rb +16 -0
- data/lib/shoes/mock.rb +33 -0
- data/lib/shoes/mock/animation.rb +8 -0
- data/lib/shoes/mock/app.rb +49 -0
- data/lib/shoes/mock/arc.rb +9 -0
- data/lib/shoes/mock/background.rb +10 -0
- data/lib/shoes/mock/border.rb +7 -0
- data/lib/shoes/mock/button.rb +22 -0
- data/lib/shoes/mock/check.rb +24 -0
- data/lib/shoes/mock/clickable.rb +8 -0
- data/lib/shoes/mock/common_methods.rb +12 -0
- data/lib/shoes/mock/dialog.rb +13 -0
- data/lib/shoes/mock/download.rb +16 -0
- data/lib/shoes/mock/font.rb +15 -0
- data/lib/shoes/mock/image.rb +13 -0
- data/lib/shoes/mock/image_pattern.rb +8 -0
- data/lib/shoes/mock/input_box.rb +30 -0
- data/lib/shoes/mock/keypress.rb +11 -0
- data/lib/shoes/mock/keyrelease.rb +11 -0
- data/lib/shoes/mock/line.rb +14 -0
- data/lib/shoes/mock/link.rb +11 -0
- data/lib/shoes/mock/list_box.rb +19 -0
- data/lib/shoes/mock/oval.rb +11 -0
- data/lib/shoes/mock/packager.rb +13 -0
- data/lib/shoes/mock/progress.rb +10 -0
- data/lib/shoes/mock/radio.rb +27 -0
- data/lib/shoes/mock/rect.rb +14 -0
- data/lib/shoes/mock/shape.rb +20 -0
- data/lib/shoes/mock/slot.rb +16 -0
- data/lib/shoes/mock/sound.rb +8 -0
- data/lib/shoes/mock/star.rb +14 -0
- data/lib/shoes/mock/text_block.rb +36 -0
- data/lib/shoes/mock/timer.rb +8 -0
- data/lib/shoes/not_implemented_error.rb +4 -0
- data/lib/shoes/oval.rb +20 -0
- data/lib/shoes/packager.rb +26 -0
- data/lib/shoes/point.rb +54 -0
- data/lib/shoes/progress.rb +25 -0
- data/lib/shoes/radio.rb +15 -0
- data/lib/shoes/rect.rb +21 -0
- data/lib/shoes/renamed_delegate.rb +15 -0
- data/lib/shoes/shape.rb +159 -0
- data/lib/shoes/slot.rb +276 -0
- data/lib/shoes/slot_contents.rb +51 -0
- data/lib/shoes/sound.rb +18 -0
- data/lib/shoes/span.rb +16 -0
- data/lib/shoes/star.rb +50 -0
- data/lib/shoes/text.rb +24 -0
- data/lib/shoes/text_block.rb +142 -0
- data/lib/shoes/text_block_dimensions.rb +51 -0
- data/lib/shoes/timer.rb +14 -0
- data/lib/shoes/ui/cli.rb +67 -0
- data/lib/shoes/ui/picker.rb +47 -0
- data/lib/shoes/url.rb +44 -0
- data/lib/shoes/version.rb +3 -0
- data/lib/shoes/widget.rb +67 -0
- data/shoes-core.gemspec +22 -0
- data/spec/shoes/animation_spec.rb +71 -0
- data/spec/shoes/app_spec.rb +484 -0
- data/spec/shoes/arc_spec.rb +51 -0
- data/spec/shoes/background_spec.rb +47 -0
- data/spec/shoes/border_spec.rb +46 -0
- data/spec/shoes/builtin_methods_spec.rb +110 -0
- data/spec/shoes/button_spec.rb +44 -0
- data/spec/shoes/check_spec.rb +35 -0
- data/spec/shoes/color_spec.rb +408 -0
- data/spec/shoes/common/inspect_spec.rb +26 -0
- data/spec/shoes/common/remove_spec.rb +38 -0
- data/spec/shoes/common/style_normalizer_spec.rb +28 -0
- data/spec/shoes/common/style_spec.rb +147 -0
- data/spec/shoes/configuration_spec.rb +36 -0
- data/spec/shoes/constants_spec.rb +38 -0
- data/spec/shoes/dialog_spec.rb +171 -0
- data/spec/shoes/dimension_spec.rb +433 -0
- data/spec/shoes/dimensions_spec.rb +837 -0
- data/spec/shoes/download_spec.rb +146 -0
- data/spec/shoes/flow_spec.rb +133 -0
- data/spec/shoes/font_spec.rb +37 -0
- data/spec/shoes/framework_learning_spec.rb +30 -0
- data/spec/shoes/gradient_spec.rb +32 -0
- data/spec/shoes/helpers/fake_element.rb +17 -0
- data/spec/shoes/helpers/inspect_helpers.rb +5 -0
- data/spec/shoes/helpers/sample17_helper.rb +66 -0
- data/spec/shoes/image_spec.rb +68 -0
- data/spec/shoes/images/shoe.jpg +0 -0
- data/spec/shoes/input_box_spec.rb +80 -0
- data/spec/shoes/integration_spec.rb +20 -0
- data/spec/shoes/internal_app_spec.rb +141 -0
- data/spec/shoes/keypress_spec.rb +11 -0
- data/spec/shoes/keyrelease_spec.rb +12 -0
- data/spec/shoes/line_spec.rb +87 -0
- data/spec/shoes/link_spec.rb +118 -0
- data/spec/shoes/list_box_spec.rb +74 -0
- data/spec/shoes/logger/ruby_spec.rb +8 -0
- data/spec/shoes/logger_spec.rb +45 -0
- data/spec/shoes/oval_spec.rb +24 -0
- data/spec/shoes/packager_spec.rb +25 -0
- data/spec/shoes/point_spec.rb +71 -0
- data/spec/shoes/progress_spec.rb +54 -0
- data/spec/shoes/radio_spec.rb +32 -0
- data/spec/shoes/rect_spec.rb +39 -0
- data/spec/shoes/renamed_delegate_spec.rb +70 -0
- data/spec/shoes/shape_spec.rb +106 -0
- data/spec/shoes/shared_examples/button.rb +6 -0
- data/spec/shoes/shared_examples/changeable.rb +26 -0
- data/spec/shoes/shared_examples/clickable.rb +5 -0
- data/spec/shoes/shared_examples/common_methods.rb +35 -0
- data/spec/shoes/shared_examples/dimensions.rb +32 -0
- data/spec/shoes/shared_examples/dsl.rb +44 -0
- data/spec/shoes/shared_examples/dsl/animate.rb +29 -0
- data/spec/shoes/shared_examples/dsl/arc.rb +45 -0
- data/spec/shoes/shared_examples/dsl/background.rb +26 -0
- data/spec/shoes/shared_examples/dsl/border.rb +10 -0
- data/spec/shoes/shared_examples/dsl/button.rb +5 -0
- data/spec/shoes/shared_examples/dsl/cap.rb +6 -0
- data/spec/shoes/shared_examples/dsl/check.rb +11 -0
- data/spec/shoes/shared_examples/dsl/edit_box.rb +8 -0
- data/spec/shoes/shared_examples/dsl/edit_line.rb +8 -0
- data/spec/shoes/shared_examples/dsl/editable_element.rb +29 -0
- data/spec/shoes/shared_examples/dsl/fill.rb +27 -0
- data/spec/shoes/shared_examples/dsl/flow.rb +15 -0
- data/spec/shoes/shared_examples/dsl/gradient.rb +62 -0
- data/spec/shoes/shared_examples/dsl/image.rb +21 -0
- data/spec/shoes/shared_examples/dsl/line.rb +9 -0
- data/spec/shoes/shared_examples/dsl/nofill.rb +6 -0
- data/spec/shoes/shared_examples/dsl/nostroke.rb +6 -0
- data/spec/shoes/shared_examples/dsl/oval.rb +88 -0
- data/spec/shoes/shared_examples/dsl/pattern.rb +34 -0
- data/spec/shoes/shared_examples/dsl/progress.rb +7 -0
- data/spec/shoes/shared_examples/dsl/rect.rb +92 -0
- data/spec/shoes/shared_examples/dsl/rgb.rb +26 -0
- data/spec/shoes/shared_examples/dsl/shape.rb +57 -0
- data/spec/shoes/shared_examples/dsl/star.rb +111 -0
- data/spec/shoes/shared_examples/dsl/stroke.rb +30 -0
- data/spec/shoes/shared_examples/dsl/strokewidth.rb +19 -0
- data/spec/shoes/shared_examples/dsl/style.rb +32 -0
- data/spec/shoes/shared_examples/dsl/text_elements.rb +81 -0
- data/spec/shoes/shared_examples/dsl/video.rb +5 -0
- data/spec/shoes/shared_examples/dsl_app_context.rb +8 -0
- data/spec/shoes/shared_examples/hover_leave.rb +11 -0
- data/spec/shoes/shared_examples/parent.rb +6 -0
- data/spec/shoes/shared_examples/scroll.rb +41 -0
- data/spec/shoes/shared_examples/shared_element_method.rb +60 -0
- data/spec/shoes/shared_examples/slot.rb +394 -0
- data/spec/shoes/shared_examples/state.rb +19 -0
- data/spec/shoes/shared_examples/style.rb +82 -0
- data/spec/shoes/slot_spec.rb +186 -0
- data/spec/shoes/sound_spec.rb +15 -0
- data/spec/shoes/span_spec.rb +112 -0
- data/spec/shoes/spec_helper.rb +24 -0
- data/spec/shoes/stack_spec.rb +79 -0
- data/spec/shoes/star_spec.rb +48 -0
- data/spec/shoes/text_block_dimensions_spec.rb +75 -0
- data/spec/shoes/text_block_spec.rb +270 -0
- data/spec/shoes/url_spec.rb +68 -0
- data/spec/shoes/widget_spec.rb +70 -0
- data/spec/shoes_spec.rb +44 -0
- data/spec/spec_helper.rb +19 -0
- data/static/downloading.png +0 -0
- data/static/shoes-icon-blue.png +0 -0
- data/static/shoes-icon-brown.png +0 -0
- data/static/shoes-icon.png +0 -0
- metadata +366 -0
data/lib/shoes/url.rb
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
class Shoes
|
|
2
|
+
# Backwards compatibility, kind of likely to be removed
|
|
3
|
+
def self.inherited(base_class)
|
|
4
|
+
base_class.send :include, URL # include is private, therefore send
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
module URL
|
|
8
|
+
attr_accessor :app
|
|
9
|
+
|
|
10
|
+
Shoes::App.subscribe_to_dsl_methods self
|
|
11
|
+
|
|
12
|
+
def self.included(base_class)
|
|
13
|
+
base_class.extend URLDefiner
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def self.urls
|
|
17
|
+
@urls ||= {}
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
module URLDefiner
|
|
22
|
+
def url(page, method)
|
|
23
|
+
page = convert_page_to_regex(page)
|
|
24
|
+
url_class = self
|
|
25
|
+
|
|
26
|
+
Shoes::URL.urls[page] = proc do |app, arg|
|
|
27
|
+
new_url_instance = url_class.new
|
|
28
|
+
new_url_instance.app = app
|
|
29
|
+
|
|
30
|
+
if arg
|
|
31
|
+
new_url_instance.send(method, arg)
|
|
32
|
+
else
|
|
33
|
+
new_url_instance.send method
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
private
|
|
39
|
+
|
|
40
|
+
def convert_page_to_regex(page)
|
|
41
|
+
/^#{page}$/
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
data/lib/shoes/widget.rb
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
class Shoes
|
|
2
|
+
# This is the superclass for creating custom Shoes widgets.
|
|
3
|
+
#
|
|
4
|
+
# To use, inherit from {Shoes::Widget}. You get a few magical effects:
|
|
5
|
+
#
|
|
6
|
+
# * When you inherit from {Shoes::Widget}, you get a method in your Apps to
|
|
7
|
+
# create your widgets. The method is lower- and snake-cased. It returns
|
|
8
|
+
# an instance of your widget class.
|
|
9
|
+
# * Your widgets delegate missing methods to their app object. This
|
|
10
|
+
# allows you to use the Shoes DSL within your widgets.
|
|
11
|
+
#
|
|
12
|
+
# @example
|
|
13
|
+
# class SayHello < Shoes::Widget
|
|
14
|
+
# def initialize word
|
|
15
|
+
# para "Hello #{word}", stroke: green, size: 80
|
|
16
|
+
# end
|
|
17
|
+
# end
|
|
18
|
+
#
|
|
19
|
+
# Shoes.app do
|
|
20
|
+
# say_hello 'Shoes'
|
|
21
|
+
# end
|
|
22
|
+
#
|
|
23
|
+
class Widget
|
|
24
|
+
include Common::Inspect
|
|
25
|
+
|
|
26
|
+
Shoes::App.subscribe_to_dsl_methods self
|
|
27
|
+
|
|
28
|
+
attr_accessor :parent
|
|
29
|
+
attr_writer :app
|
|
30
|
+
|
|
31
|
+
class << self
|
|
32
|
+
attr_accessor :app
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# lookup a bit more complicated as during initialize we do
|
|
36
|
+
# not have @app yet...
|
|
37
|
+
def app
|
|
38
|
+
@app || self.class.app
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def self.inherited(klass, &_blk)
|
|
42
|
+
dsl_method = dsl_method_name(klass)
|
|
43
|
+
Shoes::App.new_dsl_method(dsl_method) do |*args, &blk|
|
|
44
|
+
# we set app 2 times because widgets execute most of their code
|
|
45
|
+
# straight in initialize. I dunno if there is a good way of setting
|
|
46
|
+
# an @app instance variable before initialize is executed. We could
|
|
47
|
+
# hand it over in #initialize but that would break the interface
|
|
48
|
+
# and people would have to set it themselves or make sure to call
|
|
49
|
+
# super so for not it's like this.
|
|
50
|
+
# Setting the ref on the instance is important as we might have
|
|
51
|
+
# instances of the same widget in different Shoes::Apps so each one
|
|
52
|
+
# needs to save the reference to the one it was started with
|
|
53
|
+
klass.app = self
|
|
54
|
+
widget_instance = klass.new(*args, &blk)
|
|
55
|
+
widget_instance.app = self
|
|
56
|
+
widget_instance.parent = @__app__.current_slot
|
|
57
|
+
widget_instance
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def self.dsl_method_name(klass)
|
|
62
|
+
klass.to_s[/(^|::)(\w+)$/, 2]
|
|
63
|
+
.gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
|
|
64
|
+
.gsub(/([a-z\d])([A-Z])/, '\1_\2').downcase
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
data/shoes-core.gemspec
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
|
2
|
+
require File.expand_path('lib/shoes/core/version')
|
|
3
|
+
|
|
4
|
+
Gem::Specification.new do |s|
|
|
5
|
+
s.name = "shoes-core"
|
|
6
|
+
s.version = Shoes::Core::VERSION
|
|
7
|
+
s.platform = Gem::Platform::RUBY
|
|
8
|
+
s.authors = ["Team Shoes"]
|
|
9
|
+
s.email = ["shoes@librelist.com"]
|
|
10
|
+
s.homepage = "https://github.com/shoes/shoes4"
|
|
11
|
+
s.summary = %q{The best little DSL for the best little GUI toolkit for Ruby.}
|
|
12
|
+
s.description = %q{Shoes is the best little GUI toolkit for Ruby. Shoes makes building for Mac, Windows, and Linux super simple. This is the DSL for writing your app. You'll need a backend to run it.}
|
|
13
|
+
s.license = 'MIT'
|
|
14
|
+
|
|
15
|
+
s.files = `git ls-files`.split($/)
|
|
16
|
+
s.test_files = s.files.grep(%r{^(test|spec|features)/})
|
|
17
|
+
s.require_paths = ["lib"]
|
|
18
|
+
|
|
19
|
+
# Curious why we don't install shoes? See ext/Rakefile for the nitty-gritty.
|
|
20
|
+
s.executables = ['shoes-picker', 'shoes-stub']
|
|
21
|
+
s.extensions = ['ext/install/Rakefile']
|
|
22
|
+
end
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
require 'shoes/spec_helper'
|
|
2
|
+
|
|
3
|
+
shared_examples_for Shoes::Animation do
|
|
4
|
+
it "should start" do
|
|
5
|
+
subject.start
|
|
6
|
+
expect(subject).not_to be_stopped
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
it "should stop" do
|
|
10
|
+
subject.stop
|
|
11
|
+
expect(subject).to be_stopped
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
it "should toggle on" do
|
|
15
|
+
subject.stop
|
|
16
|
+
subject.toggle
|
|
17
|
+
expect(subject).not_to be_stopped
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
it "should toggle off" do
|
|
21
|
+
subject.start
|
|
22
|
+
subject.toggle
|
|
23
|
+
expect(subject).to be_stopped
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
it "increments frame" do
|
|
27
|
+
frame = subject.current_frame
|
|
28
|
+
subject.increment_frame
|
|
29
|
+
expect(subject.current_frame).to eq(frame + 1)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
describe Shoes::Animation do
|
|
34
|
+
let(:app) { double('app', current_slot: slot) }
|
|
35
|
+
let(:slot) { double('slot', create_bound_block: bound_block) }
|
|
36
|
+
let(:app_gui) { double('app gui') }
|
|
37
|
+
let(:opts) { {} }
|
|
38
|
+
let(:block) { double('block') }
|
|
39
|
+
let(:bound_block) { double('bound block') }
|
|
40
|
+
subject { Shoes::Animation.new( app, opts, block ) }
|
|
41
|
+
|
|
42
|
+
before :each do
|
|
43
|
+
expect(app).to receive(:gui) { app_gui }
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
it_behaves_like Shoes::Animation
|
|
47
|
+
|
|
48
|
+
it "sets default framerate" do
|
|
49
|
+
expect(subject.framerate).to eq(10)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
it "sets current frame to 0" do
|
|
53
|
+
expect(subject.current_frame).to eq(0)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
it "calls through slot's context" do
|
|
57
|
+
expect(subject.blk).to eq(bound_block)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
it { is_expected.not_to be_stopped }
|
|
61
|
+
|
|
62
|
+
describe "with framerate" do
|
|
63
|
+
let(:opts) { {:framerate => 36, :app => app} }
|
|
64
|
+
|
|
65
|
+
it "sets framerate" do
|
|
66
|
+
expect(subject.framerate).to eq(36)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
it_behaves_like Shoes::Animation
|
|
70
|
+
end
|
|
71
|
+
end
|
|
@@ -0,0 +1,484 @@
|
|
|
1
|
+
require 'shoes/spec_helper'
|
|
2
|
+
|
|
3
|
+
describe Shoes::App do
|
|
4
|
+
let(:input_blk) { Proc.new {} }
|
|
5
|
+
let(:opts) { Hash.new }
|
|
6
|
+
subject(:app) { Shoes::App.new(opts, &input_blk) }
|
|
7
|
+
|
|
8
|
+
after do
|
|
9
|
+
Shoes.unregister_all
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
it_behaves_like "DSL container"
|
|
13
|
+
it { is_expected.to respond_to :clipboard }
|
|
14
|
+
it { is_expected.to respond_to :clipboard= }
|
|
15
|
+
it { is_expected.to respond_to :owner }
|
|
16
|
+
|
|
17
|
+
# For Shoes 3 compatibility
|
|
18
|
+
it "exposes self as #app" do
|
|
19
|
+
expect(app.app).to eq(app)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
describe "initialize" do
|
|
23
|
+
let(:input_blk) { Proc.new {} }
|
|
24
|
+
|
|
25
|
+
it "initializes style hash", :qt do
|
|
26
|
+
style = Shoes::App.new.style
|
|
27
|
+
expect(style.class).to eq(Hash)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
context "console" do
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
context "defaults" do
|
|
34
|
+
let(:opts) { Hash.new }
|
|
35
|
+
let(:defaults) { Shoes::InternalApp::DEFAULT_OPTIONS }
|
|
36
|
+
|
|
37
|
+
it "sets width", :qt do
|
|
38
|
+
expect(subject.width).to eq defaults[:width]
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
it "sets height", :qt do
|
|
42
|
+
expect(subject.height).to eq defaults[:height]
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
it 'has an absolute_left of 0' do
|
|
46
|
+
expect(subject.absolute_left).to eq 0
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
it 'has an absolute_top of 0' do
|
|
50
|
+
expect(subject.absolute_top).to eq 0
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
describe "inspect" do
|
|
54
|
+
include InspectHelpers
|
|
55
|
+
|
|
56
|
+
it "shows title in #to_s" do
|
|
57
|
+
expect(subject.to_s).to eq("(Shoes::App \"#{defaults.fetch :title}\")")
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
it "shows title in #inspect" do
|
|
61
|
+
expect(subject.inspect).to match("(Shoes::App:#{shoes_object_id_pattern} \"#{defaults.fetch :title}\")")
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
context "from opts" do
|
|
67
|
+
let(:opts) { {:width => 150, :height => 2, :title => "Shoes::App Spec", :resizable => false} }
|
|
68
|
+
|
|
69
|
+
it "sets width", :qt do
|
|
70
|
+
expect(subject.width).to eq opts[:width]
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
it "sets height", :qt do
|
|
74
|
+
expect(subject.height).to eq opts[:height]
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
it "passes opts to InternalApp" do
|
|
78
|
+
expect(Shoes::InternalApp).to receive(:new).with(kind_of(Shoes::App), opts).and_call_original
|
|
79
|
+
subject
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
it 'initializes a flow with the right parameters' do
|
|
83
|
+
expect(Shoes::Flow).to receive(:new).with(anything, anything,
|
|
84
|
+
{width: opts[:width],
|
|
85
|
+
height: opts[:height]}).
|
|
86
|
+
and_call_original
|
|
87
|
+
subject
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
context "when registering" do
|
|
92
|
+
before :each do
|
|
93
|
+
Shoes.unregister_all
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
it "registers" do
|
|
97
|
+
old_apps_length = Shoes.apps.length
|
|
98
|
+
subject
|
|
99
|
+
expect(Shoes.apps.length).to eq(old_apps_length + 1)
|
|
100
|
+
expect(Shoes.apps).to include(subject)
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
describe "style with defaults" do
|
|
106
|
+
let(:default_styles) { Shoes::Common::Style::DEFAULT_STYLES }
|
|
107
|
+
|
|
108
|
+
it "sets app defaults" do
|
|
109
|
+
expect(app.style).to eq(default_styles)
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
it "merges new styles with existing styles" do
|
|
113
|
+
subject.style strokewidth: 4
|
|
114
|
+
expect(subject.style).to eq(default_styles.merge(strokewidth: 4))
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
default_styles = Shoes::Common::Style::DEFAULT_STYLES
|
|
118
|
+
|
|
119
|
+
default_styles.each do |key, value|
|
|
120
|
+
describe "#{key}" do
|
|
121
|
+
it "defaults to #{value}" do
|
|
122
|
+
expect(subject.style[key]).to eq(value)
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
it "passes default to objects" do
|
|
126
|
+
expect(subject.line(0, 100, 100, 0).style[key]).to eq(value)
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
describe "default styles" do
|
|
134
|
+
it "are independent among Shoes::App instances" do
|
|
135
|
+
app1 = Shoes::App.new
|
|
136
|
+
app2 = Shoes::App.new
|
|
137
|
+
|
|
138
|
+
app1.strokewidth 10
|
|
139
|
+
expect(app1.line(0, 100, 100, 0).style[:strokewidth]).to eq(10)
|
|
140
|
+
|
|
141
|
+
# .. but does not affect app2
|
|
142
|
+
expect(app2.line(0, 100, 100, 0).style[:strokewidth]).not_to eq(10)
|
|
143
|
+
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
describe "app-level style setter" do
|
|
149
|
+
let(:goldenrod) { Shoes::COLORS[:goldenrod] }
|
|
150
|
+
|
|
151
|
+
pattern_styles = Shoes::DSL::PATTERN_APP_STYLES
|
|
152
|
+
other_styles = Shoes::DSL::OTHER_APP_STYLES
|
|
153
|
+
|
|
154
|
+
pattern_styles.each do |style|
|
|
155
|
+
it "sets #{style} for objects" do
|
|
156
|
+
subject.public_send(style, goldenrod)
|
|
157
|
+
expect(subject.line(0, 100, 100, 0).style[style]).to eq(goldenrod)
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
other_styles.each do |style|
|
|
162
|
+
it "sets #{style} for objects" do
|
|
163
|
+
subject.public_send(style, 'val')
|
|
164
|
+
expect(subject.line(0, 100, 100, 0).style[style]).to eq('val')
|
|
165
|
+
end
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
describe "connecting with gui" do
|
|
171
|
+
let(:gui) { app.instance_variable_get(:@__app__).gui }
|
|
172
|
+
|
|
173
|
+
describe "clipboard" do
|
|
174
|
+
it "gets clipboard" do
|
|
175
|
+
expect(gui).to receive(:clipboard)
|
|
176
|
+
subject.clipboard
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
it "sets clipboard" do
|
|
180
|
+
expect(gui).to receive(:clipboard=).with("test")
|
|
181
|
+
subject.clipboard = "test"
|
|
182
|
+
end
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
describe "quitting" do
|
|
186
|
+
it "#quit tells the GUI to quit" do
|
|
187
|
+
expect(gui).to receive :quit
|
|
188
|
+
subject.quit
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
it '#close tells the GUI to quit' do
|
|
192
|
+
expect(gui).to receive :quit
|
|
193
|
+
subject.close
|
|
194
|
+
end
|
|
195
|
+
end
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
describe "#started?" do
|
|
199
|
+
it "checks the window has been displayed or not" do
|
|
200
|
+
subject.started?
|
|
201
|
+
end
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
describe 'Execution context' do
|
|
205
|
+
it 'starts with self as the execution context' do
|
|
206
|
+
my_self = nil
|
|
207
|
+
app = Shoes.app do my_self = self end
|
|
208
|
+
expect(my_self).to eq app
|
|
209
|
+
end
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
describe '#append' do
|
|
213
|
+
let(:input_blk) {Proc.new do append do para 'Hi' end end}
|
|
214
|
+
|
|
215
|
+
it 'understands append' do
|
|
216
|
+
expect(subject).to respond_to :append
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
it 'should receive a call to what is called in the append block' do
|
|
220
|
+
expect_any_instance_of(Shoes::App).to receive :para
|
|
221
|
+
subject
|
|
222
|
+
end
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
describe '#resize' do
|
|
226
|
+
it 'understands resize' do
|
|
227
|
+
expect(subject).to respond_to :resize
|
|
228
|
+
end
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
describe 'fullscreen' do
|
|
232
|
+
context 'defaults' do
|
|
233
|
+
it 'is not fullscreen' do
|
|
234
|
+
expect(app).not_to be_fullscreen
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
it 'can enter fullscreen' do
|
|
238
|
+
app.fullscreen = true
|
|
239
|
+
expect(app).to be_fullscreen
|
|
240
|
+
end
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
describe 'going into fullscreen and back out again' do
|
|
244
|
+
let(:defaults) { Shoes::InternalApp::DEFAULT_OPTIONS }
|
|
245
|
+
|
|
246
|
+
before :each do
|
|
247
|
+
app.fullscreen = true
|
|
248
|
+
app.fullscreen = false
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
# Failing on Mac fullscreen doesnt seem to work see #397
|
|
252
|
+
it 'is not in fullscreen', :fails_on_osx do
|
|
253
|
+
expect(app).not_to be_fullscreen
|
|
254
|
+
end
|
|
255
|
+
|
|
256
|
+
# Failing on Mac fullscreen doesnt seem to work see #397
|
|
257
|
+
it 'has its origina', :fails_on_osx do
|
|
258
|
+
expect(app.width).to eq(defaults[:width])
|
|
259
|
+
end
|
|
260
|
+
|
|
261
|
+
# Failing on Mac fullscreen doesnt seem to work see #397
|
|
262
|
+
it 'has its original height', :fails_on_osx do
|
|
263
|
+
expect(app.height).to eq(defaults[:height])
|
|
264
|
+
end
|
|
265
|
+
end
|
|
266
|
+
end
|
|
267
|
+
|
|
268
|
+
describe '#clear' do
|
|
269
|
+
let(:input_blk) do
|
|
270
|
+
Proc.new do
|
|
271
|
+
para 'Hello'
|
|
272
|
+
end
|
|
273
|
+
end
|
|
274
|
+
let(:internal_app) {subject.instance_variable_get(:@__app__)}
|
|
275
|
+
|
|
276
|
+
it 'has initial contents' do
|
|
277
|
+
expect(subject.contents).to_not be_empty
|
|
278
|
+
end
|
|
279
|
+
|
|
280
|
+
it 'removes everything (regression)' do
|
|
281
|
+
subject.clear
|
|
282
|
+
expect(subject.contents).to be_empty
|
|
283
|
+
end
|
|
284
|
+
end
|
|
285
|
+
|
|
286
|
+
describe "#gutter" do
|
|
287
|
+
context "when app has a scrollbar" do
|
|
288
|
+
let(:input_opts) { {width: 100, height: 100} }
|
|
289
|
+
let(:input_block) { Proc.new { para "Round peg, square hole" * 200 } }
|
|
290
|
+
|
|
291
|
+
it "has gutter of 16" do
|
|
292
|
+
expect(app.gutter).to be_within(2).of(16)
|
|
293
|
+
end
|
|
294
|
+
end
|
|
295
|
+
|
|
296
|
+
context "when app has no scrollbar" do
|
|
297
|
+
let(:input_block) { Proc.new { para "Round peg, square hole" } }
|
|
298
|
+
|
|
299
|
+
it "has gutter of 16" do
|
|
300
|
+
expect(app.gutter).to be_within(2).of(16)
|
|
301
|
+
end
|
|
302
|
+
end
|
|
303
|
+
end
|
|
304
|
+
|
|
305
|
+
describe "#parent" do
|
|
306
|
+
context "for a top-level element (not explicitly in a slot)" do
|
|
307
|
+
it "returns the top_slot" do
|
|
308
|
+
my_parent = nil
|
|
309
|
+
app = Shoes.app do
|
|
310
|
+
flow do
|
|
311
|
+
my_parent = parent
|
|
312
|
+
end
|
|
313
|
+
end
|
|
314
|
+
expect(my_parent).to eq app.instance_variable_get(:@__app__).top_slot
|
|
315
|
+
end
|
|
316
|
+
end
|
|
317
|
+
|
|
318
|
+
context "for an element within a slot" do
|
|
319
|
+
it "returns the enclosing slot" do
|
|
320
|
+
my_parent = nil
|
|
321
|
+
my_stack = nil
|
|
322
|
+
app = Shoes.app do
|
|
323
|
+
my_stack = stack do
|
|
324
|
+
flow do
|
|
325
|
+
my_parent = parent
|
|
326
|
+
end
|
|
327
|
+
end
|
|
328
|
+
end
|
|
329
|
+
|
|
330
|
+
expect(my_parent).to eq my_stack
|
|
331
|
+
end
|
|
332
|
+
end
|
|
333
|
+
|
|
334
|
+
end
|
|
335
|
+
|
|
336
|
+
describe "additional context" do
|
|
337
|
+
it "fails on unknown method" do
|
|
338
|
+
expect { subject.asdf }.to raise_error(NoMethodError)
|
|
339
|
+
end
|
|
340
|
+
|
|
341
|
+
it "calls through to context if available" do
|
|
342
|
+
context = double("context", asdf: nil)
|
|
343
|
+
expect(context).to receive(:asdf)
|
|
344
|
+
|
|
345
|
+
subject.eval_with_additional_context(context) do
|
|
346
|
+
asdf
|
|
347
|
+
end
|
|
348
|
+
end
|
|
349
|
+
|
|
350
|
+
it "clears context when finished" do
|
|
351
|
+
context = double("context")
|
|
352
|
+
|
|
353
|
+
captured_context = nil
|
|
354
|
+
subject.eval_with_additional_context(context) do
|
|
355
|
+
captured_context = @__additional_context__
|
|
356
|
+
end
|
|
357
|
+
|
|
358
|
+
expect(captured_context).to eq(context)
|
|
359
|
+
expect(subject.instance_variable_get(:@__additional_context__)).to be_nil
|
|
360
|
+
end
|
|
361
|
+
|
|
362
|
+
it "still clears context when failure in eval" do
|
|
363
|
+
context = double("context")
|
|
364
|
+
|
|
365
|
+
expect do
|
|
366
|
+
subject.eval_with_additional_context(context) { raise "O_o" }
|
|
367
|
+
end.to raise_error(RuntimeError)
|
|
368
|
+
|
|
369
|
+
expect(subject.instance_variable_get(:@__additional_context__)).to be_nil
|
|
370
|
+
end
|
|
371
|
+
end
|
|
372
|
+
|
|
373
|
+
describe 'subscribing to DSL methods' do
|
|
374
|
+
|
|
375
|
+
class TestSubscribeClass
|
|
376
|
+
attr_reader :app
|
|
377
|
+
def initialize(app)
|
|
378
|
+
@app = app
|
|
379
|
+
end
|
|
380
|
+
Shoes::App.subscribe_to_dsl_methods(self)
|
|
381
|
+
end
|
|
382
|
+
|
|
383
|
+
let(:subscribed_instance) {TestSubscribeClass.new subject}
|
|
384
|
+
|
|
385
|
+
AUTO_SUBSCRIBED_CLASSES = [Shoes::App, Shoes::URL, Shoes::Widget]
|
|
386
|
+
SUBSCRIBED_CLASSES = AUTO_SUBSCRIBED_CLASSES + [TestSubscribeClass]
|
|
387
|
+
|
|
388
|
+
describe '.subscribe_to_dsl_methods' do
|
|
389
|
+
it 'has its instances respond to the dsl methods of the app' do
|
|
390
|
+
expect(subscribed_instance).to respond_to :para, :image
|
|
391
|
+
end
|
|
392
|
+
|
|
393
|
+
it 'delegates does methods to the passed in app' do
|
|
394
|
+
expect(subject).to receive(:para)
|
|
395
|
+
subscribed_instance.para
|
|
396
|
+
end
|
|
397
|
+
|
|
398
|
+
SUBSCRIBED_CLASSES.each do |klazz|
|
|
399
|
+
it "#{klazz} responds to a regular DSL method" do
|
|
400
|
+
expect(klazz).to be_public_method_defined(:para)
|
|
401
|
+
end
|
|
402
|
+
end
|
|
403
|
+
end
|
|
404
|
+
|
|
405
|
+
describe '.new_dsl_method (for widget method notifications etc.)' do
|
|
406
|
+
|
|
407
|
+
before :each do
|
|
408
|
+
Shoes::App.new_dsl_method :widget_method do
|
|
409
|
+
# noop
|
|
410
|
+
end
|
|
411
|
+
end
|
|
412
|
+
|
|
413
|
+
SUBSCRIBED_CLASSES.each do |klazz|
|
|
414
|
+
it "#{klazz} now responds to this method" do
|
|
415
|
+
expect(klazz).to be_public_method_defined(:widget_method)
|
|
416
|
+
end
|
|
417
|
+
end
|
|
418
|
+
end
|
|
419
|
+
|
|
420
|
+
describe 'DELEGATE_METHODS' do
|
|
421
|
+
subject {Shoes::App::DELEGATE_METHODS}
|
|
422
|
+
|
|
423
|
+
describe 'does not include general ruby object methods' do
|
|
424
|
+
it {is_expected.not_to include :new, :initialize}
|
|
425
|
+
end
|
|
426
|
+
|
|
427
|
+
describe 'it has access to Shoes app and DSL methods' do
|
|
428
|
+
it {is_expected.to include :para, :rect, :stack, :flow, :image, :location}
|
|
429
|
+
end
|
|
430
|
+
|
|
431
|
+
describe 'it does not have access to private methods' do
|
|
432
|
+
it {is_expected.not_to include :pop_style, :style_normalizer, :create}
|
|
433
|
+
end
|
|
434
|
+
|
|
435
|
+
describe 'there are blacklisted methods that wreck havoc' do
|
|
436
|
+
it {is_expected.not_to include :parent, :app}
|
|
437
|
+
end
|
|
438
|
+
end
|
|
439
|
+
|
|
440
|
+
end
|
|
441
|
+
end
|
|
442
|
+
|
|
443
|
+
describe "App registry" do
|
|
444
|
+
subject { Shoes.apps }
|
|
445
|
+
|
|
446
|
+
before :each do
|
|
447
|
+
Shoes.unregister_all
|
|
448
|
+
end
|
|
449
|
+
|
|
450
|
+
it "only exposes a copy" do
|
|
451
|
+
subject << double("app")
|
|
452
|
+
expect(Shoes.apps.length).to eq(0)
|
|
453
|
+
end
|
|
454
|
+
|
|
455
|
+
context "with no apps" do
|
|
456
|
+
it { is_expected.to be_empty }
|
|
457
|
+
end
|
|
458
|
+
|
|
459
|
+
context "with one app" do
|
|
460
|
+
let(:app) { double('app') }
|
|
461
|
+
before :each do
|
|
462
|
+
Shoes.register(app)
|
|
463
|
+
end
|
|
464
|
+
|
|
465
|
+
its(:length) { should eq(1) }
|
|
466
|
+
it "marks first app as main app" do
|
|
467
|
+
expect(Shoes.main_app).to be(app)
|
|
468
|
+
end
|
|
469
|
+
end
|
|
470
|
+
|
|
471
|
+
context "with two apps" do
|
|
472
|
+
let(:app_1) { double("app 1") }
|
|
473
|
+
let(:app_2) { double("app 2") }
|
|
474
|
+
|
|
475
|
+
before :each do
|
|
476
|
+
[app_1, app_2].each { |a| Shoes.register(a) }
|
|
477
|
+
end
|
|
478
|
+
|
|
479
|
+
its(:length) { should eq(2) }
|
|
480
|
+
it "marks first app as main app" do
|
|
481
|
+
expect(Shoes.main_app).to be(app_1)
|
|
482
|
+
end
|
|
483
|
+
end
|
|
484
|
+
end
|