scad4r 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ lib/**/*.rb
2
+ bin/*
3
+ -
4
+ features/**/*.feature
5
+ LICENSE.txt
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/.simplecov ADDED
@@ -0,0 +1,55 @@
1
+ require 'simplecov-csv'
2
+
3
+ def isolation_mode?
4
+ ENV.fetch("ISOLATION_MODE",false)
5
+ end
6
+
7
+ def stats_mode?
8
+ ENV.fetch("STATS_MODE", false)
9
+ end
10
+
11
+ module SimpleCov::Formatter
12
+ class MutedHTMLFormatter < HTMLFormatter
13
+ def puts(*args)
14
+ end
15
+ end
16
+
17
+ class MutedCSVFormatter < CSVFormatter
18
+ def puts(*args)
19
+ end
20
+ end
21
+
22
+ class MutedMergedFormatter
23
+ def format(results)
24
+ [MutedHTMLFormatter, MutedCSVFormatter].each do |formatter|
25
+ formatter.new.format(results)
26
+ end
27
+ end
28
+ end
29
+
30
+ class MergedFormatter
31
+ def format(results)
32
+ [HTMLFormatter, CSVFormatter].each do |formatter|
33
+ formatter.new.format(results)
34
+ end
35
+ end
36
+ end
37
+ end
38
+
39
+ if isolation_mode?
40
+ SimpleCov.formatter = SimpleCov::Formatter::MutedCSVFormatter
41
+ SimpleCov.use_merging false
42
+ elsif stats_mode?
43
+ SimpleCov.formatter = SimpleCov::Formatter::MutedCSVFormatter
44
+ else
45
+ SimpleCov.formatter = SimpleCov::Formatter::MergedFormatter
46
+ end
47
+
48
+ SimpleCov.start do
49
+ add_filter 'bin/'
50
+ add_filter 'features/'
51
+ add_filter 'spec/'
52
+
53
+ add_group "Use Cases", "use_cases"
54
+ add_group "Entities", "lib"
55
+ end
data/Gemfile ADDED
@@ -0,0 +1,18 @@
1
+ source "http://rubygems.org"
2
+
3
+ gem "bundler"
4
+
5
+ group :development do
6
+ gem "growl"
7
+ gem "guard"
8
+ gem "guard-rspec"
9
+
10
+ gem "jeweler", "~> 1.8.3"
11
+
12
+ gem "rdoc"
13
+ gem "rspec"
14
+ gem "rb-fsevent"
15
+
16
+ gem "simplecov"
17
+ gem "simplecov-csv"
18
+ end
data/Guardfile ADDED
@@ -0,0 +1,5 @@
1
+ guard :rspec do
2
+ watch(%r{^spec/.+_spec\.rb$})
3
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
4
+ watch('spec/spec_helper.rb') { "spec" }
5
+ end
data/LICENSE.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2012 Caleb Buxton
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,19 @@
1
+ = scad4r
2
+
3
+ Description goes here.
4
+
5
+ == Contributing to scad4r
6
+
7
+ * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet.
8
+ * Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it.
9
+ * Fork the project.
10
+ * Start a feature/bugfix branch.
11
+ * Commit and push until you are happy with your contribution.
12
+ * Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
13
+ * Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
14
+
15
+ == Copyright
16
+
17
+ Copyright (c) 2013 Caleb Buxton. See LICENSE.txt for
18
+ further details.
19
+
data/Rakefile ADDED
@@ -0,0 +1,46 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rubygems'
4
+ require 'bundler'
5
+
6
+ begin
7
+ Bundler.setup(:default, :development)
8
+ rescue Bundler::BundlerError => e
9
+ $stderr.puts e.message
10
+ $stderr.puts "Run `bundle install` to install missing gems"
11
+ exit e.status_code
12
+ end
13
+ require 'rake'
14
+
15
+ require 'jeweler'
16
+ Jeweler::Tasks.new do |gem|
17
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
18
+ gem.name = "scad4r"
19
+ gem.homepage = "http://github.com/cpb/scad4r"
20
+ gem.license = "MIT"
21
+ gem.summary = %Q{Ruby wrapper for OpenSCAD}
22
+ gem.description = %Q{Provides Ruby affordances for scripting OpenSCAD}
23
+ gem.email = "me@cpb.ca"
24
+ gem.authors = ["Caleb Buxton"]
25
+ # dependencies defined in Gemfile
26
+ end
27
+ Jeweler::RubygemsDotOrgTasks.new
28
+
29
+ require 'rspec/core'
30
+ require 'rspec/core/rake_task'
31
+ RSpec::Core::RakeTask.new(:spec) do |spec|
32
+ spec.pattern = FileList['spec/**/*_spec.rb']
33
+ spec.rspec_opts = "-r simplecov -p"
34
+ end
35
+
36
+ task :default => [:spec]
37
+
38
+ require 'rdoc/task'
39
+ Rake::RDocTask.new do |rdoc|
40
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
41
+
42
+ rdoc.rdoc_dir = 'rdoc'
43
+ rdoc.title = "scad4r #{version}"
44
+ rdoc.rdoc_files.include('README*')
45
+ rdoc.rdoc_files.include('lib/**/*.rb')
46
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
@@ -0,0 +1,55 @@
1
+ module Scad4r
2
+ class Notification
3
+ class << self
4
+ def parse(result)
5
+ if error = result.fetch(:error, false)
6
+ Array(new(error: error))
7
+ else
8
+ timings = if real = result.fetch(:real,nil)
9
+ new(success: real)
10
+ else
11
+ nil
12
+ end
13
+ Array(result.fetch(:warnings,nil)).map do |warning|
14
+ new(warning: warning)
15
+ end + Array(result.fetch(:echos,nil)).map do |echo|
16
+ new(echo: echo)
17
+ end + Array(timings)
18
+ end
19
+ end
20
+ end
21
+
22
+ attr_reader :message
23
+ def initialize(attributes={})
24
+ @type, @message = attributes.to_a.pop
25
+ end
26
+
27
+ def image
28
+ case @type
29
+ when :error
30
+ :error
31
+ when :warning
32
+ :error
33
+ when :echo, :success
34
+ :success
35
+ end
36
+ end
37
+
38
+ def title
39
+ "openscad #{@type.to_s.upcase}"
40
+ end
41
+
42
+ def priority
43
+ case @type
44
+ when :error
45
+ 2
46
+ when :warning
47
+ 1
48
+ when :echo
49
+ 1
50
+ when :success
51
+ -1
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,51 @@
1
+ module Scad4r
2
+ class ResultParser
3
+ def parse(result)
4
+ case result
5
+ when %r{Parser error in line (\d+): (.*)$}
6
+ {error: "#{$2} line #{$1}"}
7
+ when %r{WARNING:}, %r{ECHO:}
8
+ extract_timings(result).merge({
9
+ warnings: extract_warnings(result),
10
+ echos: extract_echos(result)})
11
+ else
12
+ extract_timings(result)
13
+ end
14
+ end
15
+
16
+ protected
17
+ def extract_warnings(result)
18
+ find_messages(result, "WARNING")
19
+ end
20
+
21
+ def extract_echos(result)
22
+ find_messages(result, "ECHO")
23
+ end
24
+
25
+ def extract_timings(result)
26
+ {real: extract_time(result, :real),
27
+ user: extract_time(result, :user),
28
+ sys: extract_time(result, :sys)
29
+ }
30
+ end
31
+
32
+ private
33
+
34
+ def find_messages(result, message)
35
+ found_messages = []
36
+ message_regexp = /^#{message}: ([^\n]*)$/m
37
+ scanner = StringScanner.new(result)
38
+ while message = scanner.scan_until(message_regexp)
39
+ found_messages << scanner.matched.match(message_regexp)[1]
40
+ end
41
+
42
+ found_messages
43
+ end
44
+
45
+ def extract_time(result, type)
46
+ if matching = result.match(/([\d\.]+) #{type}/)
47
+ matching[1]
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,79 @@
1
+ module Scad4r
2
+ class Runner
3
+ class PassThrough
4
+ def parse(result)
5
+ {result: result}
6
+ end
7
+ end
8
+
9
+ def initialize(options = {})
10
+ @options = {format: :stl,
11
+ constants: {},
12
+ parser: PassThrough.new,
13
+ timed: true}.merge(options)
14
+ end
15
+
16
+ def run(path, options = {})
17
+ net_options = @options.merge(options)
18
+
19
+ parser = net_options.fetch(:parser)
20
+
21
+ # provide a reasonable default
22
+ net_options = {output: output_file(path, net_options)}.merge(net_options)
23
+
24
+ io = IO.popen(openscad_invocation(path, net_options))
25
+
26
+ result_hash = parser.parse io.read
27
+
28
+ result_hash.merge({output: net_options.fetch(:output)})
29
+ end
30
+
31
+ private
32
+
33
+ def openscad_invocation(path, options)
34
+ [*openscad_command(options),*runtime_arguments(path, options), err: [:child, :out]]
35
+ end
36
+
37
+ def openscad_command(options)
38
+ if options.fetch(:timed)
39
+ %w(time openscad)
40
+ else
41
+ "openscad"
42
+ end
43
+ end
44
+
45
+ def runtime_arguments(path, options)
46
+ arguments = []
47
+
48
+ arguments << "-o #{options.fetch(:output)}"
49
+
50
+ arguments.push(*setting_constants(options.fetch(:constants)))
51
+
52
+ # input file
53
+ arguments << path.to_s
54
+ end
55
+
56
+ def output_file(path, options)
57
+ extension = options.fetch(:format)
58
+ Pathname.new(path).sub_ext(".#{extension}")
59
+ end
60
+
61
+ def setting_constants(assignments)
62
+ assignments.inject([]) do |constants, (name, value)|
63
+ constant = "#{name}="
64
+
65
+ case value
66
+ when String
67
+ constant << value.inspect
68
+ when Symbol
69
+ constant << value.to_s.inspect
70
+ else
71
+ constant << value.to_s
72
+ end
73
+
74
+ constants << "-D '#{constant}'"
75
+ end
76
+ end
77
+
78
+ end
79
+ end
data/lib/scad4r.rb ADDED
@@ -0,0 +1,2 @@
1
+ module Scad4r
2
+ end
data/scad4r.gemspec ADDED
@@ -0,0 +1,90 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = "scad4r"
8
+ s.version = "0.1.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Caleb Buxton"]
12
+ s.date = "2013-01-26"
13
+ s.description = "Provides Ruby affordances for scripting OpenSCAD"
14
+ s.email = "me@cpb.ca"
15
+ s.extra_rdoc_files = [
16
+ "LICENSE.txt",
17
+ "README.rdoc"
18
+ ]
19
+ s.files = [
20
+ ".document",
21
+ ".rspec",
22
+ ".simplecov",
23
+ "Gemfile",
24
+ "Guardfile",
25
+ "LICENSE.txt",
26
+ "README.rdoc",
27
+ "Rakefile",
28
+ "VERSION",
29
+ "lib/scad4r.rb",
30
+ "lib/scad4r/notification.rb",
31
+ "lib/scad4r/result_parser.rb",
32
+ "lib/scad4r/runner.rb",
33
+ "scad4r.gemspec",
34
+ "spec/fixtures/scad/cube.csg",
35
+ "spec/fixtures/scad/cube.scad",
36
+ "spec/fixtures/scad/cube.stl",
37
+ "spec/lib/scad4r/notification_spec.rb",
38
+ "spec/lib/scad4r/result_parser_spec.rb",
39
+ "spec/lib/scad4r/runner_spec.rb",
40
+ "spec/lib/scad4r_spec.rb",
41
+ "spec/shared_examples.rb",
42
+ "spec/spec_helper.rb",
43
+ "spec/support/openscad_execution_matcher.rb"
44
+ ]
45
+ s.homepage = "http://github.com/cpb/scad4r"
46
+ s.licenses = ["MIT"]
47
+ s.require_paths = ["lib"]
48
+ s.rubygems_version = "1.8.23"
49
+ s.summary = "Ruby wrapper for OpenSCAD"
50
+
51
+ if s.respond_to? :specification_version then
52
+ s.specification_version = 3
53
+
54
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
55
+ s.add_runtime_dependency(%q<bundler>, [">= 0"])
56
+ s.add_development_dependency(%q<growl>, [">= 0"])
57
+ s.add_development_dependency(%q<guard>, [">= 0"])
58
+ s.add_development_dependency(%q<guard-rspec>, [">= 0"])
59
+ s.add_development_dependency(%q<jeweler>, ["~> 1.8.3"])
60
+ s.add_development_dependency(%q<rdoc>, [">= 0"])
61
+ s.add_development_dependency(%q<rspec>, [">= 0"])
62
+ s.add_development_dependency(%q<rb-fsevent>, [">= 0"])
63
+ s.add_development_dependency(%q<simplecov>, [">= 0"])
64
+ s.add_development_dependency(%q<simplecov-csv>, [">= 0"])
65
+ else
66
+ s.add_dependency(%q<bundler>, [">= 0"])
67
+ s.add_dependency(%q<growl>, [">= 0"])
68
+ s.add_dependency(%q<guard>, [">= 0"])
69
+ s.add_dependency(%q<guard-rspec>, [">= 0"])
70
+ s.add_dependency(%q<jeweler>, ["~> 1.8.3"])
71
+ s.add_dependency(%q<rdoc>, [">= 0"])
72
+ s.add_dependency(%q<rspec>, [">= 0"])
73
+ s.add_dependency(%q<rb-fsevent>, [">= 0"])
74
+ s.add_dependency(%q<simplecov>, [">= 0"])
75
+ s.add_dependency(%q<simplecov-csv>, [">= 0"])
76
+ end
77
+ else
78
+ s.add_dependency(%q<bundler>, [">= 0"])
79
+ s.add_dependency(%q<growl>, [">= 0"])
80
+ s.add_dependency(%q<guard>, [">= 0"])
81
+ s.add_dependency(%q<guard-rspec>, [">= 0"])
82
+ s.add_dependency(%q<jeweler>, ["~> 1.8.3"])
83
+ s.add_dependency(%q<rdoc>, [">= 0"])
84
+ s.add_dependency(%q<rspec>, [">= 0"])
85
+ s.add_dependency(%q<rb-fsevent>, [">= 0"])
86
+ s.add_dependency(%q<simplecov>, [">= 0"])
87
+ s.add_dependency(%q<simplecov-csv>, [">= 0"])
88
+ end
89
+ end
90
+
@@ -0,0 +1,3 @@
1
+ group() {
2
+ cube(size = [10, 10, 10], center = false);
3
+ }
@@ -0,0 +1 @@
1
+ cube(10);
@@ -0,0 +1,86 @@
1
+ solid OpenSCAD_Model
2
+ facet normal -1 0 0
3
+ outer loop
4
+ vertex 0 0 10
5
+ vertex 0 10 10
6
+ vertex 0 0 0
7
+ endloop
8
+ endfacet
9
+ facet normal -1 0 0
10
+ outer loop
11
+ vertex 0 0 0
12
+ vertex 0 10 10
13
+ vertex 0 10 0
14
+ endloop
15
+ endfacet
16
+ facet normal 0 0 1
17
+ outer loop
18
+ vertex 0 0 10
19
+ vertex 10 0 10
20
+ vertex 10 10 10
21
+ endloop
22
+ endfacet
23
+ facet normal 0 0 1
24
+ outer loop
25
+ vertex 0 10 10
26
+ vertex 0 0 10
27
+ vertex 10 10 10
28
+ endloop
29
+ endfacet
30
+ facet normal 0 -1 0
31
+ outer loop
32
+ vertex 0 0 0
33
+ vertex 10 0 0
34
+ vertex 10 0 10
35
+ endloop
36
+ endfacet
37
+ facet normal 0 -1 0
38
+ outer loop
39
+ vertex 0 0 10
40
+ vertex 0 0 0
41
+ vertex 10 0 10
42
+ endloop
43
+ endfacet
44
+ facet normal 0 0 -1
45
+ outer loop
46
+ vertex 0 10 0
47
+ vertex 10 10 0
48
+ vertex 0 0 0
49
+ endloop
50
+ endfacet
51
+ facet normal 0 0 -1
52
+ outer loop
53
+ vertex 0 0 0
54
+ vertex 10 10 0
55
+ vertex 10 0 0
56
+ endloop
57
+ endfacet
58
+ facet normal 0 1 0
59
+ outer loop
60
+ vertex 0 10 10
61
+ vertex 10 10 10
62
+ vertex 0 10 0
63
+ endloop
64
+ endfacet
65
+ facet normal 0 1 0
66
+ outer loop
67
+ vertex 0 10 0
68
+ vertex 10 10 10
69
+ vertex 10 10 0
70
+ endloop
71
+ endfacet
72
+ facet normal 1 0 0
73
+ outer loop
74
+ vertex 10 0 0
75
+ vertex 10 10 0
76
+ vertex 10 10 10
77
+ endloop
78
+ endfacet
79
+ facet normal 1 0 0
80
+ outer loop
81
+ vertex 10 0 10
82
+ vertex 10 0 0
83
+ vertex 10 10 10
84
+ endloop
85
+ endfacet
86
+ endsolid OpenSCAD_Model
@@ -0,0 +1,72 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
2
+
3
+ require 'scad4r/notification'
4
+
5
+ module Scad4r
6
+ describe Notification do
7
+ let(:notifications) { described_class.parse(scad4r_result) }
8
+ subject { notifications }
9
+
10
+ let(:high_priority) { 2}
11
+ let(:medium_priority) { 1 }
12
+ let(:low_priority) { -1 }
13
+
14
+ let(:mock_result) {
15
+ {error: nil,
16
+ echos: nil,
17
+ warnings: nil,
18
+ real: nil}
19
+ }
20
+ context "with errors" do
21
+ subject { notifications.first }
22
+ let(:scad4r_result) { mock_result.merge(error: "error message") }
23
+
24
+ its(:priority) { should eql(high_priority) }
25
+ its(:title) { should eql("openscad ERROR") }
26
+ its(:image) { should eql(:error) }
27
+ its(:message) { should eql(scad4r_result[:error]) }
28
+ end
29
+
30
+ context "with timings" do
31
+ subject { notifications.first }
32
+ let(:scad4r_result) { mock_result.merge(real: "0m0.555s") }
33
+
34
+ its(:priority) { should eql(low_priority) }
35
+ its(:title) { should eql("openscad SUCCESS") }
36
+ its(:image) { should eql(:success) }
37
+ its(:message) { should eql("0m0.555s") }
38
+ end
39
+
40
+ context "with one warning" do
41
+ subject { notifications.first }
42
+ let(:scad4r_result) { mock_result.merge(warnings: ["the warning message"]) }
43
+
44
+ its(:priority) { should eql(medium_priority) }
45
+ its(:title) { should eql("openscad WARNING") }
46
+ its(:image) { should eql(:error) }
47
+ its(:message) { should eql(scad4r_result[:warnings].first) }
48
+ end
49
+
50
+ context "with many warnings" do
51
+ let(:scad4r_result) { mock_result.merge(warnings: ["the warning message", "somany"]) }
52
+
53
+ it {should have(2).items}
54
+ end
55
+
56
+ context "with one echo" do
57
+ subject { notifications.first }
58
+ let(:scad4r_result) { mock_result.merge(echos: ["the echo message"]) }
59
+
60
+ its(:priority) { should eql(medium_priority) }
61
+ its(:title) { should eql("openscad ECHO") }
62
+ its(:image) { should eql(:success) }
63
+ its(:message) { should eql(scad4r_result[:echos].first) }
64
+ end
65
+
66
+ context "with many echos" do
67
+ let(:scad4r_result) { mock_result.merge(echos: ["the echo message", "somany"]) }
68
+
69
+ it {should have(2).items}
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,117 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
2
+
3
+ require 'scad4r/result_parser'
4
+
5
+ require 'ostruct'
6
+
7
+ module Scad4r
8
+ describe ResultParser do
9
+ subject { OpenStruct.new(described_class.new.parse(scad_result)) }
10
+
11
+ context "with errors" do
12
+ let(:scad_result) { <<-END
13
+ Parser error in line 47: syntax error
14
+
15
+ END
16
+ }
17
+ its(:error) { should eql("syntax error line 47") }
18
+ end
19
+
20
+ context "with warnings" do
21
+ let(:scad_result) { <<-END
22
+ Compiling library '/Users/caleb/Things/jhead_nozzel/nozzel_mounting.scad'.
23
+ compiled module: 0x1044198b0
24
+ /Users/caleb/Things/jhead_nozzel/nozzel_mounting.scad: 0x1044198b0
25
+ Compiling library '/Users/caleb/Things/jhead_nozzel/jhead.scad'.
26
+ compiled module: 0x104413da0
27
+ Compiling library '/Users/caleb/Things/jhead_nozzel/screws.scad'.
28
+ compiled module: 0x101ac6020
29
+ /Users/caleb/Things/jhead_nozzel/screws.scad: 0x101ac6020
30
+ /Users/caleb/Things/jhead_nozzel/jhead.scad: 0x104413da0
31
+ ECHO: [-20, -5, -4.39, 0]
32
+ WARNING: Ignoring unknown module 'foobar'.
33
+ END
34
+ }
35
+
36
+ its(:warnings) { should include("Ignoring unknown module 'foobar'.")}
37
+ its(:error) { should be_nil }
38
+ end
39
+
40
+ context "with echo" do
41
+ let(:scad_result) { <<-END
42
+ Compiling library '/Users/caleb/Things/jhead_nozzel/nozzel_mounting.scad'.
43
+ compiled module: 0x1044198b0
44
+ /Users/caleb/Things/jhead_nozzel/nozzel_mounting.scad: 0x1044198b0
45
+ Compiling library '/Users/caleb/Things/jhead_nozzel/jhead.scad'.
46
+ compiled module: 0x104413da0
47
+ Compiling library '/Users/caleb/Things/jhead_nozzel/screws.scad'.
48
+ compiled module: 0x101ac6020
49
+ /Users/caleb/Things/jhead_nozzel/screws.scad: 0x101ac6020
50
+ /Users/caleb/Things/jhead_nozzel/jhead.scad: 0x104413da0
51
+ ECHO: [-20, -5, -4.39, 0]
52
+ WARNING: Ignoring unknown module 'foobar'.
53
+ END
54
+ }
55
+
56
+ its(:echos) { should include("[-20, -5, -4.39, 0]")}
57
+ its(:error) { should be_nil }
58
+ end
59
+
60
+ context "with echo and warnings" do
61
+ let(:scad_result) { <<-END
62
+ Compiling library '/Users/caleb/Things/jhead_nozzel/nozzel_mounting.scad'.
63
+ compiled module: 0x1044198b0
64
+ /Users/caleb/Things/jhead_nozzel/nozzel_mounting.scad: 0x1044198b0
65
+ Compiling library '/Users/caleb/Things/jhead_nozzel/jhead.scad'.
66
+ compiled module: 0x104413da0
67
+ Compiling library '/Users/caleb/Things/jhead_nozzel/screws.scad'.
68
+ compiled module: 0x101ac6020
69
+ /Users/caleb/Things/jhead_nozzel/screws.scad: 0x101ac6020
70
+ /Users/caleb/Things/jhead_nozzel/jhead.scad: 0x104413da0
71
+ ECHO: [-20, -5, -4.39, 0]
72
+ WARNING: Ignoring unknown module 'foobar'.
73
+ END
74
+ }
75
+
76
+ its(:echos) { should include("[-20, -5, -4.39, 0]")}
77
+ its(:warnings) { should include("Ignoring unknown module 'foobar'.")}
78
+ end
79
+
80
+ context "with many echo and warnings" do
81
+ let(:scad_result) { <<-END
82
+ Compiling library '/Users/caleb/Things/jhead_nozzel/nozzel_mounting.scad'.
83
+ compiled module: 0x101ada2a0
84
+ /Users/caleb/Things/jhead_nozzel/nozzel_mounting.scad: 0x101ada2a0
85
+ Compiling library '/Users/caleb/Things/jhead_nozzel/jhead.scad'.
86
+ compiled module: 0x101a7e670
87
+ Compiling library '/Users/caleb/Things/jhead_nozzel/screws.scad'.
88
+ compiled module: 0x10791ddd0
89
+ /Users/caleb/Things/jhead_nozzel/screws.scad: 0x10791ddd0
90
+ /Users/caleb/Things/jhead_nozzel/jhead.scad: 0x101a7e670
91
+ ECHO: [-20, -5, -4.39, 0]
92
+ WARNING: Ignoring unknown module 'foobar'.
93
+ WARNING: Ignoring unknown module 'foobar'.
94
+ ECHO: [-20, -5, -4.39, 0]
95
+ ECHO: [-20, -5, -4.39, 0]
96
+ WARNING: Ignoring unknown module 'foobar'.
97
+ WARNING: Ignoring unknown module 'foobar'.
98
+ END
99
+ }
100
+
101
+ its(:echos) { should have(3).items }
102
+ its(:warnings) { should have(4).items }
103
+ end
104
+
105
+ context "with timings" do
106
+
107
+ let(:scad_result) { <<-END
108
+ CGAL Cache insert: import(file=\"../Huxley/Print-Huxley/Indi (1728992 bytes)\nCGAL Cache insert: multmatrix([[1,0,0,20],[0,1,0,0],[0,0,1, (1728992 bytes)\nCGAL Cache insert: group(){multmatrix([[1,0,0,20],[0,1,0,0] (1728992 bytes)\nCGAL Cache insert: group(){group(){multmatrix([[1,0,0,20],[ (1728992 bytes)\nCGAL Cache insert: cylinder($fn=24,$fa=12,$fs=2,h=5,r1=1.65 (62712 bytes)\nCGAL Cache hit: cylinder($fn=24,$fa=12,$fs=2,h=5,r1=1.65 (62712 bytes)\nCGAL Cache hit: cylinder($fn=24,$fa=12,$fs=2,h=5,r1=1.65 (62712 bytes)\nCGAL Cache hit: cylinder($fn=24,$fa=12,$fs=2,h=5,r1=1.65 (62712 bytes)\nCGAL Cache insert: multmatrix([[1,0,0,7.5],[0,1,0,2.9],[0,0 (62712 bytes)\nCGAL Cache insert: multmatrix([[1,0,0,32.5],[0,1,0,2.9],[0, (62712 bytes)\nCGAL Cache insert: multmatrix([[1,0,0,32.5],[0,1,0,25.9],[0 (62712 bytes)\nCGAL Cache insert: multmatrix([[1,0,0,7.5],[0,1,0,25.9],[0, (62712 bytes)\nCGAL Cache insert: cube(size=[3,3,5],center=false); (10872 bytes)\nCGAL Cache insert: multmatrix([[0.707107,-0.707107,0,0],[0. (10872 bytes)\nCGAL Cache hit: multmatrix([[0.707107,-0.707107,0,0],[0. (10872 bytes)\nCGAL Cache insert: multmatrix([[1,0,0,-1.06066],[0,1,0,-2.1 (10872 bytes)\nCGAL Cache insert: multmatrix([[1,0,0,41.0607],[0,1,0,-2.12 (10872 bytes)\nCGAL Cache insert: cube(size=[5.83095,5.83095,5],center=fal (10872 bytes)\nCGAL Cache insert: multmatrix([[0.857493,-0.514496,0,0],[0. (10872 bytes)\nCGAL Cache hit: cube(size=[5.83095,5.83095,5],center=fal (10872 bytes)\nCGAL Cache insert: multmatrix([[0.514496,-0.857493,0,0],[0. (10872 bytes)\nCGAL Cache insert: cube(size=[40,28.8,5],center=false); (10872 bytes)\nCGAL Cache insert: group(){multmatrix([[1,0,0,7.5],[0,1,0,2 (250560 bytes)\nCGAL Cache insert: group(){multmatrix([[1,0,0,-1.06066],[0, (21648 bytes)\nCGAL Cache insert: multmatrix([[1,0,0,0],[0,1,0,25.8],[0,0, (10872 bytes)\nCGAL Cache insert: multmatrix([[1,0,0,40],[0,1,0,25.8],[0,0 (10872 bytes)\nCGAL Cache insert: difference(){cube(size=[40,28.8,5],cente (273048 bytes)\nCGAL Cache hit: group(){group(){multmatrix([[1,0,0,20],[ (1728992 bytes)\nCGAL Cache hit: difference(){cube(size=[40,28.8,5],cente (273048 bytes)\nCGAL Cache insert: group(){difference(){cube(size=[40,28.8, (273048 bytes)\nCGAL Cache insert: difference(){group(){group(){multmatrix( (1190904 bytes)\nCGAL Cache insert: multmatrix([[1,0,0,-60],[0,1,0,0],[0,0,1 (1728992 bytes)\nCGAL Cache insert: multmatrix([[1,0,0,60],[0,1,0,0],[0,0,1, (1190904 bytes)\nCGAL Cache insert: group(){multmatrix([[1,0,0,-60],[0,1,0,0 (3192752 bytes)\nObject isn't a valid 2-manifold! Modify your design.\n 52.44 real 48.14 user 0.34 sys
109
+ END
110
+ }
111
+
112
+ its(:real) { should eql("52.44") }
113
+ its(:user) { should eql("48.14") }
114
+ its(:sys) { should eql("0.34") }
115
+ end
116
+ end
117
+ end
@@ -0,0 +1,141 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
2
+
3
+ require 'scad4r/runner'
4
+
5
+ module Scad4r
6
+ describe Runner do
7
+ subject { described_class.new(timed: false) }
8
+
9
+ describe "#run" do
10
+ include OpenscadExecutionMatcher
11
+
12
+ context "when passed a path" do
13
+ let(:passed_file) {
14
+ @fixture_path.join("scad").join("cube.scad") }
15
+
16
+ it "runs with openscad" do
17
+ subject.should run_openscad.on(passed_file)
18
+
19
+ subject.run(passed_file)
20
+ end
21
+
22
+ it "is ok with a string too" do
23
+ subject.should run_openscad.on(passed_file)
24
+
25
+ subject.run(passed_file.to_s)
26
+ end
27
+
28
+ it "returns a hash describing the result" do
29
+ IO.stub(:popen).and_return(StringIO.new)
30
+ subject.run(passed_file).should be_a(Hash)
31
+ end
32
+
33
+ describe "result hash" do
34
+ before do
35
+ IO.stub(:popen).and_return(StringIO.new)
36
+ end
37
+
38
+ let(:parser) {
39
+ double("Parser", parse: {fun: :results}) }
40
+
41
+ subject { described_class.new(timed: false, parser: parser).run(passed_file) }
42
+
43
+ it "should include the output file" do
44
+ should include(output: passed_file.sub_ext(".stl"))
45
+ end
46
+
47
+ it "should inlcude the results of the parser" do
48
+ should include(fun: :results)
49
+ end
50
+ end
51
+
52
+ describe "options" do
53
+ describe "as parameters override @options" do
54
+ subject { described_class.new(timed: false, format: :stl) }
55
+
56
+ it "runs with the option" do
57
+ subject.should run_openscad.
58
+ with("-o #{passed_file.sub_ext(".csg")}").
59
+ on(passed_file)
60
+
61
+ subject.run(passed_file, format: :csg)
62
+ end
63
+ end
64
+
65
+ describe ":format" do
66
+ context "format: :stl" do
67
+ it "creates stl files" do
68
+ subject.should run_openscad.
69
+ with("-o #{passed_file.sub_ext(".stl")}").
70
+ on(passed_file)
71
+
72
+ subject.run(passed_file, format: :stl)
73
+ end
74
+ end
75
+
76
+ context "format: :csg" do
77
+ it "creates csg files" do
78
+ subject.should run_openscad.
79
+ with("-o #{passed_file.sub_ext(".csg")}").
80
+ on(passed_file)
81
+
82
+ subject.run(passed_file, format: :csg)
83
+ end
84
+ end
85
+ end
86
+
87
+ describe ":constants" do
88
+ context "constants: {one: :assignment}" do
89
+ it "runs with the constant set" do
90
+ subject.should run_openscad.
91
+ with("-D 'one=\"assignment\"'").
92
+ on(passed_file)
93
+
94
+ subject.run(passed_file, constants: {one: :assignment})
95
+ end
96
+ end
97
+
98
+ context "constants: {two: :assignments, second: 1}" do
99
+ it "runs with each constant set" do
100
+ subject.should run_openscad.
101
+ with("-D 'two=\"assignments\"'",
102
+ "-D 'second=1'").
103
+ on(passed_file)
104
+
105
+ subject.run(passed_file, constants: {two: :assignments, second: 1})
106
+ end
107
+ end
108
+ end
109
+
110
+ describe ":parser" do
111
+ context "parser: double" do
112
+ let(:parser) {
113
+ double("Scad4r Result Parser", parse: {}) }
114
+
115
+ let(:results) {
116
+ "Some string of results" }
117
+
118
+ it "parses the results with the parser" do
119
+ parser.should_receive(:parse).with(results).and_return({})
120
+
121
+ subject.should run_openscad.on(passed_file).with_results(results)
122
+
123
+ subject.run(passed_file, parser: parser)
124
+ end
125
+ end
126
+ end
127
+
128
+ describe ":timed" do
129
+ context "timed: true" do
130
+ it "should invoke with time" do
131
+ subject.should run_openscad("time","openscad").on(passed_file)
132
+
133
+ subject.run(passed_file, timed: true)
134
+ end
135
+ end
136
+ end
137
+ end
138
+ end
139
+ end
140
+ end
141
+ end
@@ -0,0 +1,4 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe Scad4r do
4
+ end
@@ -0,0 +1 @@
1
+ Dir["./spec/shared_examples/*.rb"].each {|f| require f}
@@ -0,0 +1,16 @@
1
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
3
+ require 'rspec'
4
+ require 'scad4r'
5
+
6
+ # Requires supporting files with custom matchers and macros, etc,
7
+ # in ./support/ and its subdirectories.
8
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
9
+
10
+ require 'shared_examples'
11
+
12
+ RSpec.configure do |config|
13
+ config.before(:each) do
14
+ @fixture_path = Pathname.new(File.expand_path('../fixtures/', __FILE__))
15
+ end
16
+ end
@@ -0,0 +1,35 @@
1
+ module OpenscadExecutionMatcher
2
+ extend RSpec::Matchers::DSL
3
+
4
+ matcher :run_openscad do |expected_openscad_command="openscad" |
5
+ @expected_openscad_invocation = Array(expected_openscad_command)
6
+
7
+ match do |openscad_runner|
8
+ IO.should_receive(:popen) do |arguments|
9
+ options = arguments.pop if arguments.last.is_a?(Hash)
10
+
11
+ arguments.shift(@expected_openscad_invocation.length).should eql(@expected_openscad_invocation)
12
+
13
+ Array(@expected_arguments).each do |expected_argument|
14
+ arguments.delete(expected_argument).should_not be_nil
15
+ end
16
+
17
+ arguments.last.should eql(@expected_input_file)
18
+
19
+ StringIO.new(@mock_result||"")
20
+ end
21
+ end
22
+
23
+ chain :on do |expected_input_file|
24
+ @expected_input_file = expected_input_file.to_s
25
+ end
26
+
27
+ chain :with do |expected_arguments|
28
+ @expected_arguments = Array(expected_arguments)
29
+ end
30
+
31
+ chain :with_results do |mock_result|
32
+ @mock_result = mock_result
33
+ end
34
+ end
35
+ end
metadata ADDED
@@ -0,0 +1,234 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: scad4r
3
+ version: !ruby/object:Gem::Version
4
+ prerelease:
5
+ version: 0.1.0
6
+ platform: ruby
7
+ authors:
8
+ - Caleb Buxton
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-01-26 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ type: :runtime
16
+ version_requirements: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ name: bundler
23
+ prerelease: false
24
+ requirement: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ type: :development
32
+ version_requirements: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ name: growl
39
+ prerelease: false
40
+ requirement: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ type: :development
48
+ version_requirements: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ name: guard
55
+ prerelease: false
56
+ requirement: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ - !ruby/object:Gem::Dependency
63
+ type: :development
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ name: guard-rspec
71
+ prerelease: false
72
+ requirement: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ - !ruby/object:Gem::Dependency
79
+ type: :development
80
+ version_requirements: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ~>
84
+ - !ruby/object:Gem::Version
85
+ version: 1.8.3
86
+ name: jeweler
87
+ prerelease: false
88
+ requirement: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ~>
92
+ - !ruby/object:Gem::Version
93
+ version: 1.8.3
94
+ - !ruby/object:Gem::Dependency
95
+ type: :development
96
+ version_requirements: !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ! '>='
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ name: rdoc
103
+ prerelease: false
104
+ requirement: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ! '>='
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ - !ruby/object:Gem::Dependency
111
+ type: :development
112
+ version_requirements: !ruby/object:Gem::Requirement
113
+ none: false
114
+ requirements:
115
+ - - ! '>='
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ name: rspec
119
+ prerelease: false
120
+ requirement: !ruby/object:Gem::Requirement
121
+ none: false
122
+ requirements:
123
+ - - ! '>='
124
+ - !ruby/object:Gem::Version
125
+ version: '0'
126
+ - !ruby/object:Gem::Dependency
127
+ type: :development
128
+ version_requirements: !ruby/object:Gem::Requirement
129
+ none: false
130
+ requirements:
131
+ - - ! '>='
132
+ - !ruby/object:Gem::Version
133
+ version: '0'
134
+ name: rb-fsevent
135
+ prerelease: false
136
+ requirement: !ruby/object:Gem::Requirement
137
+ none: false
138
+ requirements:
139
+ - - ! '>='
140
+ - !ruby/object:Gem::Version
141
+ version: '0'
142
+ - !ruby/object:Gem::Dependency
143
+ type: :development
144
+ version_requirements: !ruby/object:Gem::Requirement
145
+ none: false
146
+ requirements:
147
+ - - ! '>='
148
+ - !ruby/object:Gem::Version
149
+ version: '0'
150
+ name: simplecov
151
+ prerelease: false
152
+ requirement: !ruby/object:Gem::Requirement
153
+ none: false
154
+ requirements:
155
+ - - ! '>='
156
+ - !ruby/object:Gem::Version
157
+ version: '0'
158
+ - !ruby/object:Gem::Dependency
159
+ type: :development
160
+ version_requirements: !ruby/object:Gem::Requirement
161
+ none: false
162
+ requirements:
163
+ - - ! '>='
164
+ - !ruby/object:Gem::Version
165
+ version: '0'
166
+ name: simplecov-csv
167
+ prerelease: false
168
+ requirement: !ruby/object:Gem::Requirement
169
+ none: false
170
+ requirements:
171
+ - - ! '>='
172
+ - !ruby/object:Gem::Version
173
+ version: '0'
174
+ description: Provides Ruby affordances for scripting OpenSCAD
175
+ email: me@cpb.ca
176
+ executables: []
177
+ extensions: []
178
+ extra_rdoc_files:
179
+ - LICENSE.txt
180
+ - README.rdoc
181
+ files:
182
+ - .document
183
+ - .rspec
184
+ - .simplecov
185
+ - Gemfile
186
+ - Guardfile
187
+ - LICENSE.txt
188
+ - README.rdoc
189
+ - Rakefile
190
+ - VERSION
191
+ - lib/scad4r.rb
192
+ - lib/scad4r/notification.rb
193
+ - lib/scad4r/result_parser.rb
194
+ - lib/scad4r/runner.rb
195
+ - scad4r.gemspec
196
+ - spec/fixtures/scad/cube.csg
197
+ - spec/fixtures/scad/cube.scad
198
+ - spec/fixtures/scad/cube.stl
199
+ - spec/lib/scad4r/notification_spec.rb
200
+ - spec/lib/scad4r/result_parser_spec.rb
201
+ - spec/lib/scad4r/runner_spec.rb
202
+ - spec/lib/scad4r_spec.rb
203
+ - spec/shared_examples.rb
204
+ - spec/spec_helper.rb
205
+ - spec/support/openscad_execution_matcher.rb
206
+ homepage: http://github.com/cpb/scad4r
207
+ licenses:
208
+ - MIT
209
+ post_install_message:
210
+ rdoc_options: []
211
+ require_paths:
212
+ - lib
213
+ required_ruby_version: !ruby/object:Gem::Requirement
214
+ none: false
215
+ requirements:
216
+ - - ! '>='
217
+ - !ruby/object:Gem::Version
218
+ segments:
219
+ - 0
220
+ hash: 2031449955225607489
221
+ version: '0'
222
+ required_rubygems_version: !ruby/object:Gem::Requirement
223
+ none: false
224
+ requirements:
225
+ - - ! '>='
226
+ - !ruby/object:Gem::Version
227
+ version: '0'
228
+ requirements: []
229
+ rubyforge_project:
230
+ rubygems_version: 1.8.23
231
+ signing_key:
232
+ specification_version: 3
233
+ summary: Ruby wrapper for OpenSCAD
234
+ test_files: []