Hmm… I downloaded the current version, but if you look in the file you’ll see it is using the old names.
Oops I don’t use Github much and apparently I did have an old version (I just downloaded the master branch). Just discovered the releases page, and that has a newer version. Sorry for my ignorance.
NO problem, you are now smarter than before!
Actually I’m looking at the latest and somehow he has the old namespaces etc.
He may have inserted a regression by pasting from an old version ?
ADD: Which also means his change log is erroneous as to RubyZip version support.
I suggest opening an issue, or perhaps forking, fixing and do a pull request.
Oh I see now. He’s ALSO using …
… to try and use old code with newer RubyZip.
zip-zip provides a simple adapter to let all your dependencies use RubyZip v1.0.0. It is very simple and light weight, aliasing the old class names to the new.
Now the light bulb is starting to turn on!
I hate having all those rb files flying around. I wrote a little script to package it all into a single rb within my plugin module.
Create Package.rb
module BC
def self.get_requires(base_path, file_name, requires = [], level = 0)
#return if level > 10
file_path_name = file_name.end_with?('.rb') ? base_path + file_name : base_path + file_name + '.rb'
return [] unless File.exist?(file_path_name)
file = File.open(file_path_name)
file_data = file.readlines.map(&:chomp)
requires_found = file_data.select { |l| l.include?("require '") && l.lstrip[0] != '#' }.map { |r| r.split("'")[1] }
file.close
requires_found.each do |r|
next if requires.include?(r) || r == file_name
requires.push r
get_requires(base_path, r, requires, level + 1)
requires.push r
end
requires.push file_name if level == 0
#filter out duplicates
if level == 0
rq = []
requires.reverse.each { |r| rq.push(r) unless rq.include?(r) }
requires = rq.reverse
end
requires
end
def self.generate_package(base_path, loader)
requires = get_requires(base_path, loader)
#add the requires that are not referencing a file in the package
package_lines = ["module " + name]
package_lines += requires.reject { |f| File.exist?(base_path + f) || File.exist?(base_path + f + '.rb') }.map { |l| "require '" + l + "'" }
package_lines.push "\nend"
#add the file contents from each required file.
files = requires.select { |f| File.exist?(base_path + f) || File.exist?(base_path + f + '.rb') }
files.each do |f|
f_name = f.end_with?('.rb') ? base_path + f : base_path + f + '.rb'
next unless File.exist? f_name
file = File.open(f_name)
file_data = file.readlines.map(&:chomp)
#strip out requires pointing to files included in package
#strip out comments and empty lines
package_lines.push("module " + name)
package_lines.push("#" + f)
package_lines += file_data.reject { |l| l.strip[0] == '#' || l.include?("require '") || l.strip == '' }
package_lines.push "\nend"
file.close
end
#package_lines.push "\nend"
#save the package to file
output_file = loader.gsub('.rb', '') + '(packaged).rb'
open(base_path + output_file, 'w') { |f| f.puts package_lines.join("\n") }
end
end
Yea, I remember playing with a “parrot” script similar to this.
Don’t remember if I got it working as desired. I wanted it to encapsulate a gem within another namespace, rather than producing re-namespaced gem files (as your example does.)
But, … what works works.
... a note on working with files (click to expand.)
Perhaps cleaner as:
file_data = IO::readlines(file_path_name).map(&:chomp)
requires_found = file_data.select { |l|
l.include?("require '") && l.lstrip[0] != '#' }.map { |r| r.split("'")[1]
}
But it you really prefer the #readlines
instance method inherited from superclass IO
, then seek to leverage the block form of File::open
as often as you can. It automatically closes the file object, and returns the result of the block.
file_data = File::open(file_path_name) do |file|
file.readlines.map(&:chomp)
end
requires_found = file_data.select { |l|
l.include?("require '") && l.lstrip[0] != '#' }.map { |r| r.split("'")[1]
}
Also do as little as needed within the block, and save other processing for afterward outside the block, so the file stream is not left open longer than necessary.
Interesting script.
What I usually do is combine all separate .rb files into 1 big file and then add 2 modules at the top to serve as a namespace. Combining the files into 1 big file also speeds up the loading process significally.
Sorry, did not have access to my pc in the weekend. But, I see you have it all sorted out.
… by reducing the entries in the global $LOADED_FEATURES
array, which will serve to speed up searches (using string comparisons on the array members) for the require
method.
Don’t you have to strip out the requires, and make sure the files are loaded in the right order?
What is the difference? Can you shed some on my ignorance. I noticed I had to prefix the class with my namespace even when initializing the class from within my module, but i wasn’t sure why. (I’m afraid I’m revealing my ignorance )
Yes. But that can be automated by creating a dependency tree and flattening the files into 1. You just start with the first file and iterate all require
and require_relative
and remember which absolute paths have been parsed. if the current require
is requiring a new file you grab the contents and replace the require
with the contents. If the require
is pointing to a file that has already been loaded you just comment out that line. Now, if you do this recursively, you will end up with a large file, containing all sources in the correct order.
You make it sound so simple That is basically what my script does.
Do you have a similar script for packaging html/js/css into constants inside a main ruby file? Then the whole plugin could exist in a single rb except for the image assets.
Yea, as I remember, it was exactly what Ken describes that I had problems with.
The difference would be that you are creating a snapshot using a particular gem’s version for your extension. This works because you test and know that version works with your extension and the version of Ruby that SketchUp uses at that time.
This might change in the future as newer version of Ruby are distro’d with SketchUp.
My idea was a more “on the fly” approach to get around some of the gem install issues. Where an extension could request a certain gem version, and it would be encapsulated when the command was run.
I didn’t fully finish it, It was still in the try and fail stage.
I would once having the new gem code text, use Module.module_eval
and pass it the text
html_text = File.read(File.join(__dir__,"some_html_file.html"))
… and then …
html = %[#{html_text}]
… or …
HTML ||= %[#{html_text}]
You can also use #{}
string interpolation within HEREDOCs.
I see, except for the combining into 1 file part. But, this should work as well the way you do it.
Now, you will notice in write_xlsx that there are a few references to modules and classes where there is pointing to a global module while -because you subnamespaced it- actually a relative module is needed. I do not really know how to explain this in English, but, here we go: in write_xlsx you will see a lot of references that start with ::
, for example ‘::Zip’, thus, pointing to a toplevel class or module named Zip
. But, since you have subnamespaced Zip
as, for example Neil::Zip
, ::Zip
will give an error.
Yes and no. My GUI’s are react.js apps, so they are kind of packaged. But, I do not package them into a .rb file. The only reason I could see is to hide the sources? But then… Developer Console is there for anybody to see the sources.