Create a plugin that puts text in a .txt file - ruby

I am working on creating a plugin in Ruby.
On this moment I am unable to insert the coordinates, that are added to a Sketchup model, in a .txt file.
This is my code:
require 'sketchup.rb'
SKETCHUP_CONSOLE.show rescue Sketchup.send_action("showRubyPanel:")
$stdout = File.new('file.txt', 'w')
module HWmakemyownplug
def self.fileplug
model = Sketchup.active_model
#Make some coordinates.
coordinates = [[2,0,39],[0,0,1],[1,1,0]]
#Add the points in Sketchup. This works!
coordinates.each { |point| model.active_entities.add_cpoint(point) }
#Puts the coordinates to the textfile 'file.txt'. This doesn't work!
$stdout.puts(coordinates)
end #def self.fileplug
end #module makemyownplug
if (!file_loaded?(__FILE__))
#Add to the SketchUp tools menu
extensions_menu = UI.menu("Plugins")
extensions_menu.add_item("testtesttest") { HWmakemyownplug::fileplug }
# Let Ruby know we have loaded this file
file_loaded(__FILE__)
end
The coordinates have to be printed when I click on menu > plugins > testtesttest.

You forgot to close file after $stdout.puts(coordinates)
$stdout.close

Here is an example code for writing data to a JSON file instead of a simple text document.
The code can run outside of SketchUp for testing in the terminal. Just make sure to follow these steps...
Copy the code below and paste it on a ruby file (example: file.rb)
Run the script in terminal ruby file.rb or run with SketchUp.
The script will write data to JSON file and also read the content of JSON file.
The path to the JSON file is relative to the ruby file created in step one. If the script can't find the path it will create the JSON file for you.
module DeveloperName
module PluginName
require 'json'
require 'fileutils'
class Main
def initialize
path = File.dirname(__FILE__)
#json = File.join(path, 'file.json')
#content = { 'hello' => 'hello world' }.to_json
json_create(#content)
json_read(#json)
end
def json_create(content)
File.open(#json, 'w') { |f| f.write(content) }
end
def json_read(json)
if File.exist?(json)
file = File.read(json)
data_hash = JSON.parse(file)
puts "Json content: #{data_hash}"
else
msg = 'JSON file not found'
UI.messagebox(msg, MB_OK)
end
end
# # #
end
DeveloperName::PluginName::Main.new
end
end

Related

Get the full filename of the post in convecter of Jekyll

I am using markdown extension in jekyll using convecter. For example:
module Jekyll
class MyConverter < Converter
safe false
priority :high
def matches(ext)
ext =~ /^.(md|markdown)$/i
end
def output_ext(ext)
".html"
end
def my_process (content)
# something
end
def convert(content)
# Here my markdown processing
# content = my_process(content)
# Here I want to use the path to the markdown file
# puts (filename)
site = Jekyll::Site.new(#config)
converter = site.find_converter_instance(Jekyll::Converters::Markdown)
converter.convert(content)
end
end
end
Is it possible to get the full name of the file or its location for which markdown text is converted to html?
For example, I have a markdown file:
Bla bla bla.
[Text of the link](gallery)
Bla bla bla
And I want a list of the files in directory gallery. How to get a list of files from a specific directory I know, but in the convecter I need to know the full path to this markdown file. Is there any way to do that?
Use Jekyll::Hook:
module Jekyll
class MyHookProcess
class << self
def my_process(content)
# something
content
end
end
end
end
Jekyll::Hooks.register([:posts], :pre_render) do |post|
#puts ("post.date = " + post.date)
#puts ("post.path = " + post.path)
#puts ("post.url = " + post.url)
post.content = Jekyll::MyHookProcess.my_process(post.content)
end

Testing input/output with rspec and plain ruby

I am trying to create a test for a FileProcessor that reads from a text file, passes it to another class and then writes output. I made a test file and am able to access but it feels bulky. I'm also going to need to test that it writes the output in a new file and I am not sure how to set this up. I've seen a lot of tutorials but they are be rails centric. My goal is to get rid of writing the path in the test and to clean up the generated output files after each test.
describe FileProcessor do
test_file = File.dirname(__FILE__) + '/fixtures/test_input.txt'
output_file = File.dirname(__FILE__) + '/fixtures/test_output.txt'
subject {FileProcessor.new(test_file, output_file)}
describe '#read_file' do
it 'reads a file' do
expect(subject.read_file).to eq('This is a test.')
end
end
def write_file(str)
File.open("#{output_file}", "w+") { |file| file.write(str) }
end
end
How about using StringIO:
require 'stringio'
class FileProcessor
def initialize(infile, outfile)
#infile = infile
#outfile = outfile
#content = nil
end
def read_file
#content ||= #infile.read
end
def write_file(text)
#outfile.write(text)
end
end
describe FileProcessor do
let(:outfile) { StringIO.new }
subject(:file_processor) do
infile = StringIO.new('This is a test')
FileProcessor.new(infile, outfile)
end
describe '#read_file' do
it "returns correct text" do
expect(file_processor.read_file).to eq("This is a test")
end
end
describe '#write_file' do
it "writes correct text" do
file_processor.write_file("Hello world")
outfile.rewind
expect(outfile.read).to eq("Hello world")
end
end
end
There's not a great way to avoid writing the path of your input file. You could move that into a helper method, but on the other hand having the path in the test has the benefit that someone else (or you six months from now) looking at the code will know immediately where the test data comes from.
As for the output file, the simplest solution is to use Ruby's built-in Tempfile class. Tempfile.new is like File.new, except that it automatically puts the file in /tmp (or wherever your OS's temporary file directory is) and gives it a unique name. This way you don't have to worry about cleaning it up, because the next time you run the test it'll use a file with a different name (and your OS will automatically delete the file). For example:
require 'tempfile'
describe FileProcessor do
let(:test_file_path) { File.dirname(__FILE__) + '/fixtures/test_input.txt' }
let(:output_file) { Tempfile.new('test_output.txt').path }
subject { FileProcessor.new(test_file_path, output_file.path) }
describe '#read_file' do
it 'reads a file' do
expect(subject.read_file).to eq('This is a test.')
end
end
end
Using let (instead of just assigning a local variable) ensures that each example will use its own unique output file. In RSpec you should almost always prefer let.
If you want to get really serious, you could instead use the FakeFS gem, which mocks all of Ruby's built-in file-related classes (File, Pathname, etc.) so you're never writing to your actual filesystem. Here's a quick tutorial on using FakeFS: http://www.bignerdranch.com/blog/fake-it/

Access config file from any directory?

I am making a command line tool and I am using yaml to make a config file. But right now I can only access the tool when I am in the same directory as that of myprogram.yml.
private
CONFIG_FILE = 'myprogram.yml'
def write_config
config = {}
config['username']=#username
config['password']=#password
File.open(CONFIG_FILE, 'w') do |f|
f.write config.to_yaml
end
end
def read_config
config = YAML.load_file(CONFIG_FILE)
#username = config['username']
#password = config['password']
end
How can I make this file to be accessed from any directory on my computer?
You'll want to give the absolute directory of the myprogram.yml file. Right now it will look in the directory where you are executing the ruby script from. By making it absolute, the script can run anywhere and know where to find the config file.
Example:
private
CONFIG_FILE = '/Users/myuser/config/myprogram.yml'
def write_config
config = {}
config['username']=#username
config['password']=#password
File.open(CONFIG_FILE, 'w') do |f|
f.write config.to_yaml
end
end
def read_config
config = YAML.load_file(CONFIG_FILE)
#username = config['username']
#password = config['password']
end

Three Ruby classes, more than three problems?

I have three Ruby files in the same directory:
classthree.rb
otherclass.rb
samplecode.rb
Here are the contents of classthree.rb:
require './samplecode.rb'
require './otherclass.rb'
class ClassThree
def initialize()
puts "this class three here"
end
end
Here are the contents of samplecode.rb:
require './otherclass.rb'
require './classthree.rb'
class SampleCode
$smart = SampleCode.new
#sides = 3
##x = "333"
def ugly()
g = ClassThree.new
puts g
puts "monkey see"
end
def self.ugly()
s = SampleCode.new
s.ugly
puts s
puts $smart
puts "monkey see this self"
end
SampleCode.ugly
end
Here are the contents of otherclass.rb:
require './samplecode.rb'
require './classthree.rb'
END {
puts "ending"
}
BEGIN{
puts "beginning"
}
class OtherClass
def initialize()
s = SampleCode.new
s.ugly
end
end
My two questions are:
There has to be a better way than require './xyz.rb' for every class in the directory. Isn't there something like require './*.rb'?
When I run ruby otherclass.rb I get the following output:
Why do I get "beginning" and "ending" twice each??
At 1 - The best way to deal with it is to create another file. You can call it environment.rb or initialize.rb, and it would require all the needed files.
$LOAD_PATH.unshift File.dirname(__FILE__)
require 'samplecode.rb'
require 'classthree.rb'
require 'classthree.rb'
Now you only need to require this file once on the start of the application.
At 2 - You started from file 'otherclass.rb'. It displays the first 'beginning' bit and then it loads samplecode.rb file. At this point, 'otherclass.rb' has not been loaded yet - it was not required by any other file. hence samplecode.rb is rerunning whole otherclass.rb, which is being required there. Rerunning doesn't reload 'samplecode.rb' as it was already required (require checks first whether file was or was not required). That's why you're seeing those messages twice.

Require a module file and interact with its module?

In a folder I have random module files.
eg. "user.rb" that contains "module User", "customer.rb" that contains "module Customer" and so on.
I want to require all files and print out all module methods.
Here is my current code:
##data_module_methods = []
# iterate through all files in the data folder
Dir[File.join(APP_ROOT, "data", "*.rb")].each do |file|
require file
# give me the module name from the filepath (so ./data/user.rb will give me User)
data_module_name = file.split("/").[](-1).split(".").[](0).capitalize
# ERROR: print all method names, HERE IT FAILS BECAUSE data_module_name is a string and not the module:)
data_module_name.instance_methods.each do |method|
##data_module_methods << method
end
end
How could i do this?
Thanks
You can use the Kernel#const_get method to get every module by its name, so:
...
Kernel.const_get(data_module_name).instance_methods.each do |method|
...

Resources