shoes3
shoes3 copied to clipboard
Using clipboard is confusing
The usage of clipboard is confusing and not as advertised. Shoes manual stipulates that clipboard = aString will store aString into the system clipboard. Unfortunately, it is not possible to use as stipulated and it is necessary to use self.clipboard.
Moreover, a method clipboard() is used to retrieve the content of the system clipboard. The usage would be best either one rather than a mixed way, either clipboard()/clipboard(aString) or clipboard/clipboard=.
Shoes.app(:title => "Copy and Paste", :width => 450, :height => 250) {
button "copy" do
self.clipboard = "this is a Shoes string."
end
button "paste" do
para clipboard()
end
}
This echoes a recent discussion at a Shoes4 issue (that I can't find). I don't remember which choice they made or maybe they punted to just emulate Shoes 3.x . Either way, we ought to be compatible. if possible.
What might be useful is to implement a Copy (to clipboard) button on the Shoes console (along with the key chords). Who hasn't wanted to copy the console error message into a email or bug report?
This echoes a recent discussion at a Shoes4 issue (that I can't find). I don't remember which choice they made or maybe they punted to just emulate Shoes 3.x . Either way, we ought to be compatible. if possible.
Are you referring to the following fix? https://github.com/shoes/shoes4/pull/1010
They seem to gear towards for clipboard/clipboard= but couldn't find a definite choice made. shoes/shoes4#1009
What might be useful is to implement a Copy (to clipboard) button on the Shoes console (along with the key chords). Who hasn't wanted to copy the console error message into a email or bug report?
This is exactly what I am suggesting in issue #15.
It's not immediately clear to me how the definition works. It's in ruby.h (line 290) in the CANVAS_DEFS macro. I would have expected an entry in ruby.c as well.
Search for CANVAS_DEFS in https://github.com/Shoes3/shoes/blob/master/shoes/ruby.c. A tricky macro to create all the shoes_canvas_c_* and shoes_app_c_* functions and then a second set of defs to make the functions visible to Ruby.
I wonder if those macros handle the = case properly/as desired. It's only used for clipboard= and cursor=.
It seems properly handled but the whole DSL is basically flawed. The following code is to be run with Ruby (not Shoes). It simulates and simplifies what is going on with Shoes. You will notice that clipboard= is considered a local variable rather than being a Shoes class method. Here is the output:
Clipboard content:
Using clipboard
Clipboard content:
Using self.clipboard
Clipboard content: copy to self.clipboard
Shoes manual makes it clear that clipboard= should work without self. It means we either have to fix the DSL to remove the need of self or consider the alternative of using clipboard(aString). It is not possible to use self_before_instance_eval to solve the self issue because Shoes class is essentially static. For this, Shoes has seemingly a solution in https://github.com/Shoes3/shoes/blob/master/shoes/ruby.c:
// Defines a redirecting function which applies the element or transformation
// to the currently active canvas. This is used in place of the old instance_eval
// and ensures that you have access to the App's instance variables while
// assembling elements in a layout.
It may work on canvas but not on Shoes class.
class Shoes
@@clipboard = ""
def method_missing(method, *args, &block)
@self_before_instance_eval.send method, *args, &block
end
def self.app(&block)
instance_eval &block
end
def self.info(str)
puts str
end
def self.clipboard
@@clipboard
end
def self.clipboard=(value)
@@clipboard = value
end
end
Shoes.app do
info "Clipboard content: #{clipboard()}\n\n"
info "Using clipboard"
clipboard = "copy to clipboard"
info "Clipboard content: #{clipboard()}\n\n"
info "Using self.clipboard"
self.clipboard = "copy to self.clipboard"
info "Clipboard content: #{clipboard()}"
end
If I understand you correctly, clipboard= becomes an instance var somewhere in Shoes.class, Shoes.module, or Shoes.App.class. It's all bit confusing to Ruby light weights like me.
Other than typing convenience, there is no reason that clipboard() and clipboard= definitions have to be run through the macros. They could be added to both Canvas and App further down in ruby.c I'm tempted to give that a try. I might have to add some glue functions like I did for set_window_icon_path so it compiles to calling the shoes_native_clipboard_set (get) but that just replaces the generated code from the macros.
If I understand you correctly, clipboard= becomes an instance var somewhere in Shoes.class, Shoes.module, or Shoes.App.class. It's all bit confusing to Ruby light weights like me.
It is more confusing than that. I am actually saying it is a local variable as demonstrated in the following Shoes code:
Shoes.app(:title => "Copy and Paste", :width => 450, :height => 250) {
clipboard = "Is this an instance variable?"
self.clipboard = "this is a Shoes string."
para "#{clipboard()}\n"
para "#{clipboard}\n"
para "#{instance_variables}\n"
para "#{local_variables}\n"
}
The output is:
this is a Shoes string.
Is this an instance variable?
[:@main_app]
[:clipboard]
Other than typing convenience, there is no reason that clipboard() and clipboard= definitions have to be run through the macros. They could be added to both Canvas and App further down in ruby.c I'm tempted to give that a try. I might have to add some glue functions like I did for set_window_icon_path so it compiles to calling the shoes_native_clipboard_set (get) but that just replaces the generated code from the macros.
Your approach is likely to work but the advantages of moving those definitions out are still unclear at this time. It will not fix the problem with self.clipboard=. There are most likely more pressing matters.
The advantages would be "it's working as documented". The disadvantages would be some loss of Ruby-ness. or Shoes-ness. I view it a a C solution to a C problem and the existing behavior isn't all that "Shoes-y". 3.2 is only a maintenance release. That said, I don't have a huge problem with changing the manual to say to writing to the clipboard requires "self.clipboard = 'string'"
If you want to lower the priory
You most certainly can work your magic.
I'd like to mention my rationale for your consideration but perhaps something is missing. The implementation of set_window_icon_path and set_window_title for the type App are not overloading an operator. This is an important information because fullscreen= in the same type does require self.fullscreen = true (or false) to work. In fact, all the methods overloading #= need self because Ruby seems to prioritize local assignment over method calling.
What am I missing?
Investigation reveals that Ruby always consider the assignment as a local variable. There is no meta programming technique to solve this problem as far as searching on the web goes though there might be some C technique. That would be your call on this one.
Additionally, going back in time to Curious reveals that self has always been used. https://github.com/shoes/shoes/blob/1/Curious/samples/edit.rb.
Going back to Raisins reveals the manual never specified the need to use self but the sample simple-editor.rb does prove the contrary. https://github.com/shoes/shoes/blob/2/Raisins/static/manual.txt and https://github.com/shoes/shoes/blob/2/Raisins/samples/simple-editor.rb.
My recommendation is to move towards clipboard/clipboard() as well as all other methods overloading the assignment operator for consistency with other elements such as para, button, etc. If so, it would be necessary to contact Shoes4 team to ensure continuity in the change. They have the same problem with DSL as we do. Otherwise, simply update the manual to specify the need to use self.
We are at the location where Shoes is not Ruby, it only looks like Ruby! Backwards compatibility is important for a maintenance effort - thanks for digging back in the time vault. There's already differences in the manuals for 3.2 and 4. My preferences today would be to leave the code alone and fix the manual. (document the behavior of 3.2 better).
No problem. I was concerned you would dig yourself in a big hole for something that is suspected to be challenging. The code you are looking at in Shoes is never called when you write clipboard = aString. To implement a selfless method call would most likely require to monitor local variables for clipboard within the scope of App and notify the hook events on change or override Ruby's parser behaviour.
The issue remains that self is a difficult concept for newbies and its usage is inconsistent with Shoes DSL.
Let's go for your preference for now. Here is the recommended protocol:
- Fix the manual for all the methods overloading the assignment operator that requires self when called within its own block. The candidates are — App#clipboard=, App#fullscreen=, App#name=, Canvas#scroll_top=, Image#[]=, Image#path=, Video#position=, Pattern#fill=, TextBlock#cursor=, TextBlock#marker=, TextBlock#text=, Text#text=, Native#state=, EditLine#text=, EditLine#finish=, EditBox#text=, ListBox#items=, Progress#fraction=, Slider#fraction=, Check#checked=, Radio#checked=.
- Leave this ticket open and change its priority to low.
- Contact Shoes4 team with our findings, they may come up with a solution that we can backport or agree to support parenthesis methods while keeping the previous definitions for backward compatibility.