Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use a single Scarpe::App instance as self nearly everywhere #277

Merged
merged 1 commit into from
Jul 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions examples/selfitude.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
def printish(msg)
#$stderr.puts msg
File.open("/tmp/shoesy_stuff.txt", "a") do |f|
f.write(msg + "\n")
end
end

Shoes.app do
printish "Self top: #{self.inspect}" # It's an instance of Shoes::App, yes
stack do
printish "Self in stack: #{self.inspect}" # Yup, here too
end
button("Clickity") do
alert("You clicked me!")
printish "Self in button handler: #{self.inspect}" # And here too
end
end

90 changes: 87 additions & 3 deletions lib/scarpe/app.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,22 +20,24 @@ def initialize(
debug: ENV["SCARPE_DEBUG"] ? true : false,
&app_code_body
)
log_init("Scarpe::App")

if Scarpe::App.instance
@log.error("Trying to create a second Scarpe::App in the same process! Fail!")
raise "Cannot create multiple Scarpe::App objects!"
else
Scarpe::App.instance = self
end

log_init("Scarpe::App")

@do_shutdown = false

super

# This creates the DocumentRoot, including its corresponding display widget
@document_root = Scarpe::DocumentRoot.new

@slots = []

# Now create the App display widget
create_display_widget

Expand Down Expand Up @@ -68,7 +70,31 @@ def init
send_shoes_event(event_name: "init")
return if @do_shutdown

@document_root.instance_eval(&@app_code_body)
::Scarpe::App.instance.with_slot(@document_root, &@app_code_body)
end

# "Container" widgets like flows, stacks, masks and the document root
# are considered "slots" in Scarpe parlance. When a new slot is created,
# we push it here in order to track what widgets are found in that slot.
def push_slot(slot)
@slots.push(slot)
end

def pop_slot
@slots.pop
end

def current_slot
@slots[-1]
end

def with_slot(slot_item, &block)
return unless block_given?

push_slot(slot_item)
Scarpe::App.instance.instance_eval(&block)
ensure
pop_slot
end

# This isn't supposed to return. The display service should take control
Expand All @@ -85,5 +111,63 @@ def destroy(send_event: true)
@do_shutdown = true
send_shoes_event(event_name: "destroy") if send_event
end

def all_widgets
out = []

to_add = @document_root.children
until to_add.empty?
out.concat(to_add)
to_add = to_add.flat_map(&:children).compact
end

out
end

# We can add various ways to find widgets here.
# These are sort of like Shoes selectors, used for testing.
def find_widgets_by(*specs)
widgets = all_widgets
specs.each do |spec|
if spec.is_a?(Class)
widgets.select! { |w| spec === w }
elsif spec.is_a?(Symbol)
s = spec.to_s
case s[0]
when "$"
begin
# I'm not finding a global_variable_get or similar...
global_value = eval s
widgets &= [global_value]
rescue
raise "Error getting global variable: #{spec.inspect}"
end
when "@"
if app.instance_variables.include?(spec)
widgets &= [self.instance_variable_get(spec)]
else
raise "Can't find top-level instance variable: #{spec.inspect}!"
end
else
end
else
raise("Don't know how to find widgets by #{spec.inspect}!")
end
end
widgets
end
end
end

# DSL methods
class Scarpe::App
def background(...)
current_slot.background(...)
end

def border(...)
current_slot.border(...)
end

alias_method :info, :puts
end
4 changes: 2 additions & 2 deletions lib/scarpe/cats_cradle.rb
Original file line number Diff line number Diff line change
Expand Up @@ -166,9 +166,9 @@ def on_event(event, &block)
# Also, wait, what's up with span? What *is* that?
WIDGET_FINDERS.each do |finder_name, scarpe_class|
define_method(finder_name) do |*args|
root = Scarpe::App.instance.document_root
app = Scarpe::App.instance

widgets = root.find_widgets_by(scarpe_class, *args)
widgets = app.find_widgets_by(scarpe_class, *args)
raise "Found more than one #{finder_name} matching #{args.inspect}!" if widgets.size > 1
raise "Found no #{finder_name} matching #{args.inspect}!" if widgets.empty?

Expand Down
54 changes: 2 additions & 52 deletions lib/scarpe/document_root.rb
Original file line number Diff line number Diff line change
@@ -1,66 +1,16 @@
# frozen_string_literal: true

class Scarpe
class DocumentRoot < Scarpe::Widget
include Scarpe::Background

class DocumentRoot < Scarpe::Slot
def initialize
super

create_display_widget
end

# This can be absolutely huge in console output, and it's frequently printed.
# The default inspect string can be absolutely huge in console output, and it's frequently printed.
def inspect
"<Scarpe::DocumentRoot>"
end

alias_method :info, :puts

def all_widgets
out = []

to_add = self.children
until to_add.empty?
out.concat(to_add)
to_add = to_add.flat_map(&:children).compact
end

out
end

# We can add various ways to find widgets here.
# These are sort of like Shoes selectors, used for testing.
def find_widgets_by(*specs)
widgets = all_widgets
app = Scarpe::App.instance
specs.each do |spec|
if spec.is_a?(Class)
widgets.select! { |w| spec === w }
elsif spec.is_a?(Symbol)
s = spec.to_s
case s[0]
when "$"
begin
# I'm not finding a global_variable_get or similar...
global_value = eval s
widgets = [global_value]
rescue
raise "Error getting global variable: #{spec.inspect}"
end
when "@"
if app.instance_variables.include?(spec)
widgets = [app.instance_variable_get(spec)]
else
raise "Can't find top-level instance variable: #{spec.inspect}!"
end
else
end
else
raise("Don't know how to find widgets by #{spec.inspect}!")
end
end
widgets
end
end
end
47 changes: 47 additions & 0 deletions lib/scarpe/download.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# frozen_string_literal: true

require "net/http"
require "openssl"
require "nokogiri"

class Scarpe::Widget
def download(url)
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note to me: make sure we have a test for download. Is this on the right class?

Thread.new do
begin
uri = URI(url)
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE

request = Net::HTTP::Get.new(uri.request_uri)

http.request(request) do |response|
case response
when Net::HTTPSuccess
# content = response.body

# headers = response.header

html_get_title(content)
else
Scarpe.error("Failed to download content. Response code: #{response.code}")
end
end
rescue StandardError => e
Scarpe.error("Error occurred while downloading: #{e.message}")
end
end
end

private

def html_get_title(content)
doc = Nokogiri::HTML(content)

title = doc.at_css("title")&.text&.strip || ""

# headings = doc.css("h1").map(&:text)

title
end
end
7 changes: 2 additions & 5 deletions lib/scarpe/flow.rb
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
# frozen_string_literal: true

class Scarpe
class Flow < Scarpe::Widget
include Scarpe::Background
include Scarpe::Border

class Flow < Scarpe::Slot
display_properties :width, :height, :margin, :padding

def initialize(width: nil, height: "100%", margin: nil, padding: nil, &block)
Expand All @@ -13,7 +10,7 @@ def initialize(width: nil, height: "100%", margin: nil, padding: nil, &block)
# Create the display-side widget *before* instance_eval, which will add child widgets with their display widgets
create_display_widget

instance_eval(&block)
Scarpe::App.instance.with_slot(self, &block) if block_given?
end
end
end
1 change: 1 addition & 0 deletions lib/scarpe/shape.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ def initialize(left: nil, top: nil, path_commands: nil, &block)

super()
create_display_widget

instance_eval(&block) if block_given?
end
end
Expand Down
6 changes: 6 additions & 0 deletions lib/scarpe/slot.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# frozen_string_literal: true

class Scarpe::Slot < Scarpe::Widget
include Scarpe::Background
include Scarpe::Border
end
54 changes: 3 additions & 51 deletions lib/scarpe/stack.rb
Original file line number Diff line number Diff line change
@@ -1,13 +1,7 @@
# frozen_string_literal: true

require "net/http"
require "openssl"
require "nokogiri"

class Scarpe
class Stack < Scarpe::Widget
include Scarpe::Background
include Scarpe::Border
class Stack < Scarpe::Slot
include Scarpe::Spacing

display_properties :width, :height, :margin, :padding, :scroll, :margin_top, :margin_left, :margin_right, :margin_bottom, :options
Expand All @@ -21,50 +15,8 @@ def initialize(width: nil, height: "100%", margin: nil, padding: nil, scroll: fa
super

create_display_widget
# Create the display-side widget *before* instance_eval, which will add child widgets with their display widgets
instance_eval(&block) if block_given?
end
end

class Widget
def download(url)
Thread.new do
begin
uri = URI(url)
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE

request = Net::HTTP::Get.new(uri.request_uri)

http.request(request) do |response|
case response
when Net::HTTPSuccess
# content = response.body

# headers = response.header

get_title(content)
else
Scarpe.error("Failed to download content. Response code: #{response.code}")
end
end
rescue StandardError => e
Scarpe.error("Error occurred while downloading: #{e.message}")
end
end
end

private

def get_title(content)
doc = Nokogiri::HTML(content)

title = doc.at_css("title")&.text&.strip || ""

# headings = doc.css("h1").map(&:text)

title
# Create the display-side widget *before* running the block, which will add child widgets with their display widgets
Scarpe::App.instance.with_slot(self, &block) if block_given?
end
end
end
Loading
Loading