g-coder 0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ coverage
6
+ InstalledFiles
7
+ lib/bundler/man
8
+ pkg
9
+ rdoc
10
+ spec/reports
11
+ test/tmp
12
+ test/version_tmp
13
+ tmp
14
+
15
+ # YARD artifacts
16
+ .yardoc
17
+ _yardoc
18
+ doc/
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in gcoder.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2014 32leaves
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
6
+ this software and associated documentation files (the "Software"), to deal in
7
+ the Software without restriction, including without limitation the rights to
8
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9
+ the Software, and to permit persons to whom the Software is furnished to do so,
10
+ subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,4 @@
1
+ gcoder
2
+ ======
3
+
4
+ GCoder is a Ruby library to deal with GCode in various flavours. It's designed to make scripting GCode filters easy, and to work with Opal to enable web-based GCode editors/viewers.
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,23 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'gcoder/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "g-coder"
8
+ spec.version = GCoder::VERSION
9
+ spec.authors = ["32leaves"]
10
+ spec.email = ["info@32leav.es"]
11
+ spec.summary = %q{GCoder is a Ruby library to deal with GCode in various flavours.}
12
+ spec.description = %q{GCoder is designed to make scripting GCode filters easy, and to work with Opal to enable web-based GCode editors/viewers.}
13
+ spec.homepage = ""
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.5"
22
+ spec.add_development_dependency "rake"
23
+ end
@@ -0,0 +1,4 @@
1
+ require 'gcoder/dialects/default'
2
+ require 'gcoder/version'
3
+ require 'gcoder/gcode'
4
+ require 'gcoder/parser'
@@ -0,0 +1,95 @@
1
+
2
+ module GCoder
3
+
4
+ module Dialects
5
+
6
+ def self.default
7
+ map = {}
8
+ map[:C] = {}
9
+ map[:G] = {}
10
+ map[:M] = {}
11
+ map[:G][0] = :MoveRapid
12
+ map[:G][1] = :MoveByFeedrate
13
+ map[:G][2] = :ClockwiseCircularArcAtFeedrate
14
+ map[:G][3] = :CounterClockwiseCircularArcAtFeedrate
15
+ map[:G][4] = :Dwell
16
+ map[:G][9] = :ExactStopCheck
17
+ map[:G][10] = :ProgrammableParameterInput
18
+ map[:G][15] = :TurnPolarCoordinatesOffReturnToCartesianCoordinates
19
+ map[:G][16] = :TurnPolarCoordinatesOn
20
+ map[:G][17] = :SelectXYPlane
21
+ map[:G][18] = :SelectXZPlane
22
+ map[:G][19] = :SelectYZPlane
23
+ map[:G][20] = :ProgramCoordinatesAreInches
24
+ map[:G][21] = :ProgramCoordinatesAreMm
25
+ map[:G][27] = :ReferencePointReturnCheck
26
+ map[:G][28] = :ReturnToHomePosition
27
+ map[:G][29] = :ReturnFromTheReferencePosition
28
+ map[:G][30] = :ReturnToThe2nd3rdAnd4thReferencePoint
29
+ map[:G][32] = :ConstantLeadThreading
30
+ map[:G][40] = :ToolCutterCompensationOff
31
+ map[:G][41] = :ToolCutterCompensationLeft
32
+ map[:G][42] = :ToolCutterCompensationRight
33
+ map[:G][43] = :ApplyToolLengthCompensationPlus
34
+ map[:G][44] = :ApplyToolLengthCompensationMinus
35
+ map[:G][49] = :ToolLengthCompensationCancel
36
+ map[:G][50] = :ResetAllScaleFactorsTo1
37
+ map[:G][51] = :TurnOnScaleFactors
38
+ map[:G][53] = :MachineCoordinateSystem
39
+ map[:G][54] = :WorkCoordinateSystem1stWorkpiece
40
+ map[:G][55] = :WorkCoordinateSystem2ndWorkpiece
41
+ map[:G][56] = :WorkCoordinateSystem3rdWorkpiece
42
+ map[:G][57] = :WorkCoordinateSystem4thWorkpiece
43
+ map[:G][58] = :WorkCoordinateSystem5thWorkpiece
44
+ map[:G][59] = :WorkCoordinateSystem6thWorkpiece
45
+ map[:G][61] = :ExactStopCheckMode
46
+ map[:G][62] = :AutomaticCornerOverride
47
+ map[:G][63] = :TappingMode
48
+ map[:G][64] = :BestSpeedPath
49
+ map[:G][65] = :CustomMacroSimpleCall
50
+ map[:G][68] = :CoordinateSystemRotation
51
+ map[:G][69] = :CancelCoordinateSystemRotation
52
+ map[:G][73] = :HighSpeedDrillingCycle
53
+ map[:G][74] = :LeftHandTappingCycle
54
+ map[:G][76] = :FineBoringCyle
55
+ map[:G][80] = :CancelCannedCycle
56
+ map[:G][81] = :SimpleDrillingCycle
57
+ map[:G][82] = :DrillingCycleWithDwell
58
+ map[:G][83] = :PeckDrillingCycle
59
+ map[:G][84] = :TappingCycle
60
+ map[:G][85] = :BoringCannedCycleNoDwellFeedOut
61
+ map[:G][86] = :BoringCannedCycleSpindleStopRapidOut
62
+ map[:G][87] = :BackBoringCannedCycle
63
+ map[:G][88] = :BoringCannedCycleSpindleStopManualOut
64
+ map[:G][89] = :BoringCannedCycleDwellFeedOut
65
+ map[:G][90] = :AbsoluteProgrammingOfXYZ
66
+ map[:G][91] = :IncrementalProgrammingOfXYZ
67
+ map[:G][92] = :OffsetCoordinateSystemAndSaveParameters
68
+ map[:G][921] = :CancelOffsetAndZeroParameters
69
+ map[:G][922] = :CancelOffsetAndRetainParameters
70
+ map[:G][923] = :OffsetCoordinateSystemWithSavedParameters
71
+ map[:G][94] = :UnitsPerMinuteFeedModeUnitsInInchesOrMm
72
+ map[:G][95] = :UnitsPerRevolutionFeedModeUnitsInInchesOrMm
73
+ map[:G][96] = :ConstantSurfaceSpeed
74
+ map[:G][97] = :CancelConstantSurfaceSpeed
75
+ map[:G][98] = :ReturnToInitialZPlaneAfterCannedCycle
76
+ map[:G][99] = :ReturnToInitialRPlaneAfterCannedCycle
77
+ map[:M][0] = :ProgramStop
78
+ map[:M][1] = :ProgramStopOptional
79
+ map[:M][2] = :EndOfProgram
80
+ map[:M][3] = :SpindleOnCwRotation
81
+ map[:M][4] = :SpindleOnCcwRotation
82
+ map[:M][5] = :SpindleStop
83
+ map[:M][6] = :ToolChange
84
+ map[:M][7] = :MistCoolantOn
85
+ map[:M][8] = :FloodCoolantOn
86
+ map[:M][9] = :CoolantOff
87
+ map[:M][30] = :EndOfProgramRewindAndResetModes
88
+ map[:M][98] = :SubprogramCall
89
+ map[:M][99] = :ReturnFromSubprogram
90
+ map
91
+ end
92
+
93
+ end
94
+
95
+ end
@@ -0,0 +1,321 @@
1
+ require 'delegate'
2
+
3
+ class Object
4
+
5
+ #
6
+ # A combination of to_i and to_f.
7
+ # If this object is nil?, nil is returned.
8
+ # If this object is an integer, to_i is returned.
9
+ # If this object is a floating point number, to_f is returned.
10
+ #
11
+ def to_nif
12
+ if nil?
13
+ nil
14
+ elsif to_i.to_s == self
15
+ to_i
16
+ else
17
+ to_f
18
+ end
19
+ end
20
+
21
+ end
22
+
23
+ module GCoder
24
+
25
+ module GCode
26
+
27
+ class ProgramContext < SimpleDelegator
28
+ attr_accessor :position, :feedrate, :units, :absolute
29
+
30
+ def initialize(position = [0,0,0], feedrate = 0, units = :mm, absolute = false)
31
+ super({})
32
+
33
+ @position = position
34
+ @feedrate = feedrate
35
+ @units = units
36
+ @absolute = absolute
37
+ end
38
+
39
+ def absolute?; absolute; end
40
+
41
+ def update_position(pos)
42
+ if absolute
43
+ @position = @position.each_with_index.map {|e, i| pos[i] || @position[i] }
44
+ else
45
+ @position = @position.each_with_index.map {|e, i| @position[i] + (pos[i] || 0) }
46
+ end
47
+ end
48
+
49
+ def update_feedrate(feedrate)
50
+ @feedrate = feedrate unless feedrate.nil?
51
+ end
52
+ end
53
+
54
+ class Program < SimpleDelegator
55
+ include GCoder::GCode
56
+
57
+ def initialize(commands)
58
+ super(commands)
59
+ end
60
+
61
+ #
62
+ # Interpretes aspects of the GCode program, namely position, feedrate, unit of measure
63
+ # and absolute/incremental positioning. This information is made available to the optional
64
+ # block as second parameter, through a ProgramContext instance.
65
+ #
66
+ # Returns an array with two elements, the mapping result and context.
67
+ #
68
+ #
69
+ def map_with_context(&block)
70
+ ctx = ProgramContext.new
71
+
72
+ map_result = self.map do |cmd|
73
+ if block_given?
74
+ r = yield(cmd, ctx)
75
+ else
76
+ r = cmd
77
+ end
78
+
79
+ if cmd.is_a? MoveRapid or cmd.is_a? MoveByFeedrate
80
+ ctx.update_position cmd.position
81
+ ctx.update_feedrate cmd.feedrate
82
+ elsif cmd.is_a? ProgramCoordinatesAreMm
83
+ ctx.units = :mm
84
+ elsif cmd.is_a? ProgramCoordinatesAreInches
85
+ ctx.units = :inch
86
+ elsif cmd.is_a? AbsoluteProgrammingOfXYZ
87
+ ctx.absolute = true
88
+ elsif cmd.is_a? IncrementalProgrammingOfXYZ
89
+ ctx.absolute = false
90
+ end
91
+
92
+ r
93
+ end
94
+
95
+ [map_result, ctx]
96
+ end
97
+
98
+
99
+ end
100
+
101
+ class Command
102
+ attr_reader :code, :args
103
+
104
+ def initialize(code, args)
105
+ @code = code
106
+ @args = args
107
+ end
108
+
109
+ def to_s
110
+ ( [code] + args.map {|e| e.join } ).join(" ")
111
+ end
112
+
113
+ end
114
+
115
+ class Comment < Command
116
+ # Returns the text of the comment without the parentheses
117
+ def text
118
+ code
119
+ end
120
+
121
+ def to_s
122
+ "(#{code})"
123
+ end
124
+ end
125
+
126
+ class CategoryCommand < Command
127
+ end
128
+ class MotionCommand < Command
129
+
130
+ def position
131
+ [ args[:X], args[:Y], args[:Z] ].map {|x| x.to_nif }
132
+ end
133
+
134
+ def feedrate
135
+ args[:F].to_nif
136
+ end
137
+
138
+ end
139
+ class CompensationCommand < Command
140
+ end
141
+ class CoordinateCommand < Command
142
+ end
143
+ class MotionCommand < Command
144
+ end
145
+ class CannedCommand < Command
146
+ end
147
+ class CompensationCommand < Command
148
+ end
149
+ class CoordinateCommand < Command
150
+ end
151
+ class OtherCommand < Command
152
+ end
153
+ class CannedCommand < Command
154
+ end
155
+ class MCodeCommand < Command
156
+ end
157
+
158
+ class MoveRapid < MotionCommand
159
+ end
160
+ class MoveByFeedrate < MotionCommand
161
+ end
162
+ class ClockwiseCircularArcAtFeedrate < MotionCommand
163
+ end
164
+ class CounterClockwiseCircularArcAtFeedrate < MotionCommand
165
+ end
166
+ class Dwell < MotionCommand
167
+ end
168
+ class ExactStopCheck < MotionCommand
169
+ end
170
+ class ProgrammableParameterInput < CompensationCommand
171
+ end
172
+ class TurnPolarCoordinatesOffReturnToCartesianCoordinates < CoordinateCommand
173
+ end
174
+ class TurnPolarCoordinatesOn < CoordinateCommand
175
+ end
176
+ class SelectXYPlane < CoordinateCommand
177
+ end
178
+ class SelectXZPlane < CoordinateCommand
179
+ end
180
+ class SelectYZPlane < CoordinateCommand
181
+ end
182
+ class ProgramCoordinatesAreInches < CoordinateCommand
183
+ end
184
+ class ProgramCoordinatesAreMm < CoordinateCommand
185
+ end
186
+ class AbsoluteProgrammingOfXYZ < CoordinateCommand
187
+ end
188
+ class IncrementalProgrammingOfXYZ < CoordinateCommand
189
+ end
190
+ class ReferencePointReturnCheck < MotionCommand
191
+ end
192
+ class ReturnToHomePosition < MotionCommand
193
+ end
194
+ class ReturnFromTheReferencePosition < MotionCommand
195
+ end
196
+ class ReturnToThe2nd3rdAnd4thReferencePoint < MotionCommand
197
+ end
198
+ class ConstantLeadThreading < CannedCommand
199
+ end
200
+ class ToolCutterCompensationOff < CompensationCommand
201
+ end
202
+ class ToolCutterCompensationLeft < CompensationCommand
203
+ end
204
+ class ToolCutterCompensationRight < CompensationCommand
205
+ end
206
+ class ApplyToolLengthCompensationPlus < CompensationCommand
207
+ end
208
+ class ApplyToolLengthCompensationMinus < CompensationCommand
209
+ end
210
+ class ToolLengthCompensationCancel < CompensationCommand
211
+ end
212
+ class ResetAllScaleFactorsTo1 < CompensationCommand
213
+ end
214
+ class TurnOnScaleFactors < CompensationCommand
215
+ end
216
+ class MachineCoordinateSystem < CoordinateCommand
217
+ end
218
+ class WorkCoordinateSystem1stWorkpiece < CoordinateCommand
219
+ end
220
+ class WorkCoordinateSystem2ndWorkpiece < CoordinateCommand
221
+ end
222
+ class WorkCoordinateSystem3rdWorkpiece < CoordinateCommand
223
+ end
224
+ class WorkCoordinateSystem4thWorkpiece < CoordinateCommand
225
+ end
226
+ class WorkCoordinateSystem5thWorkpiece < CoordinateCommand
227
+ end
228
+ class WorkCoordinateSystem6thWorkpiece < CoordinateCommand
229
+ end
230
+ class ExactStopCheckMode < OtherCommand
231
+ end
232
+ class AutomaticCornerOverride < OtherCommand
233
+ end
234
+ class TappingMode < OtherCommand
235
+ end
236
+ class BestSpeedPath < OtherCommand
237
+ end
238
+ class CustomMacroSimpleCall < OtherCommand
239
+ end
240
+ class CoordinateSystemRotation < CoordinateCommand
241
+ end
242
+ class CancelCoordinateSystemRotation < CoordinateCommand
243
+ end
244
+ class HighSpeedDrillingCycle < CannedCommand
245
+ end
246
+ class LeftHandTappingCycle < CannedCommand
247
+ end
248
+ class FineBoringCyle < CannedCommand
249
+ end
250
+ class CancelCannedCycle < CannedCommand
251
+ end
252
+ class SimpleDrillingCycle < CannedCommand
253
+ end
254
+ class DrillingCycleWithDwell < CannedCommand
255
+ end
256
+ class PeckDrillingCycle < CannedCommand
257
+ end
258
+ class TappingCycle < CannedCommand
259
+ end
260
+ class BoringCannedCycleNoDwellFeedOut < CannedCommand
261
+ end
262
+ class BoringCannedCycleSpindleStopRapidOut < CannedCommand
263
+ end
264
+ class BackBoringCannedCycle < CannedCommand
265
+ end
266
+ class BoringCannedCycleSpindleStopManualOut < CannedCommand
267
+ end
268
+ class BoringCannedCycleDwellFeedOut < CannedCommand
269
+ end
270
+ class OffsetCoordinateSystemAndSaveParameters < CoordinateCommand
271
+ end
272
+ class ClampOfMaximumSpindleSpeed < MotionCommand
273
+ end
274
+ class CancelOffsetAndZeroParameters < CoordinateCommand
275
+ end
276
+ class CancelOffsetAndRetainParameters < CoordinateCommand
277
+ end
278
+ class OffsetCoordinateSystemWithSavedParameters < CoordinateCommand
279
+ end
280
+ class UnitsPerMinuteFeedModeUnitsInInchesOrMm < MotionCommand
281
+ end
282
+ class UnitsPerRevolutionFeedModeUnitsInInchesOrMm < MotionCommand
283
+ end
284
+ class ConstantSurfaceSpeed < MotionCommand
285
+ end
286
+ class CancelConstantSurfaceSpeed < MotionCommand
287
+ end
288
+ class ReturnToInitialZPlaneAfterCannedCycle < CannedCommand
289
+ end
290
+ class ReturnToInitialRPlaneAfterCannedCycle < CannedCommand
291
+ end
292
+ class ProgramStop < MCodeCommand
293
+ end
294
+ class ProgramStopOptional < MCodeCommand
295
+ end
296
+ class EndOfProgram < MCodeCommand
297
+ end
298
+ class SpindleOnCwRotation < MCodeCommand
299
+ end
300
+ class SpindleOnCcwRotation < MCodeCommand
301
+ end
302
+ class SpindleStop < MCodeCommand
303
+ end
304
+ class ToolChange < MCodeCommand
305
+ end
306
+ class MistCoolantOn < MCodeCommand
307
+ end
308
+ class FloodCoolantOn < MCodeCommand
309
+ end
310
+ class CoolantOff < MCodeCommand
311
+ end
312
+ class EndOfProgramRewindAndResetModes < MCodeCommand
313
+ end
314
+ class SubprogramCall < MCodeCommand
315
+ end
316
+ class ReturnFromSubprogram < MCodeCommand
317
+ end
318
+
319
+ end
320
+
321
+ end
@@ -0,0 +1,45 @@
1
+
2
+ module GCoder
3
+
4
+ class Parser
5
+
6
+ #
7
+ # Rudimentary GCode parser that also maps the commands to their respective classes according to the dialect.
8
+ #
9
+ # Returns a GCode::Program containing the commands.
10
+ #
11
+ def parse(code, dialect = GCoder::Dialects::default)
12
+ code = code.split("\n") unless code.is_a? Array
13
+
14
+ commands = code.map do |caa|
15
+ r = nil
16
+ caa.strip!
17
+ unless caa.empty?
18
+ cmd, *args = caa.strip.split(" ")
19
+ root_code = cmd[0...1]
20
+ child_code = cmd[1..-1]
21
+ args = args.inject({}) {|m,e| m[e[0...1].to_sym] = e[1..-1]; m }
22
+
23
+ if root_code == '('
24
+ r = GCoder::GCode::Comment.new(caa.strip[1...-1], {})
25
+ else
26
+ commands = dialect[root_code.to_sym]
27
+ throw "Dialect does not support #{root_code} commands" if commands.nil?
28
+
29
+ unless child_code.nil? or child_code.empty?
30
+ cmd_class = commands[child_code.to_i]
31
+ throw "Dialect does not support command: #{child_code}" if cmd_class.nil?
32
+
33
+ r = eval("GCoder::GCode::#{cmd_class}").new(cmd, args)
34
+ end
35
+ end
36
+ end
37
+ r
38
+ end.compact
39
+
40
+ GCode::Program.new(commands)
41
+ end
42
+
43
+ end
44
+
45
+ end
@@ -0,0 +1,6 @@
1
+
2
+ module GCoder
3
+
4
+ VERSION = 0.1
5
+
6
+ end
@@ -0,0 +1,13 @@
1
+ require 'rspec'
2
+ require 'spec_helper'
3
+
4
+ describe 'Default dialect' do
5
+
6
+ it 'should use only classes that exist in GCoder' do
7
+ GCoder::Dialects::default.values.map {|e| e.values }.flatten.each do |classname|
8
+ GCoder::GCode.const_defined?(classname).should be_true, "Undefined class #{classname}"
9
+ GCoder::GCode.const_get(classname).new("Code", {})
10
+ end
11
+ end
12
+
13
+ end
@@ -0,0 +1,56 @@
1
+ require 'rspec'
2
+ require 'spec_helper'
3
+
4
+ describe 'GCode program' do
5
+
6
+ it 'should maintain the correct position (in absolute mode) in map_with_context' do
7
+ program = GCoder::Parser.new.parse("""
8
+ G90
9
+ G0 X0 Y0 Z0 F140
10
+ G1 X42 Y13 Z22.2 F100.001
11
+ G0 X11.1 Y0 Z102
12
+ M0
13
+ """)
14
+
15
+ program.map_with_context.last.absolute?.should eq true
16
+ program.map_with_context {|cmd, ctx| ctx.position }.first.should eq [
17
+ [ 0, 0, 0 ],
18
+ [ 0, 0, 0 ],
19
+ [ 0, 0, 0 ],
20
+ [ 42, 13, 22.2 ],
21
+ [ 11.1, 0, 102 ]
22
+ ]
23
+ end
24
+
25
+ it 'should maintain the correct position (in relative mode) in map_with_context' do
26
+ program = GCoder::Parser.new.parse("""
27
+ G91
28
+ G0 X0 Y0 Z0 F140
29
+ G1 X42 Y13 Z22.2 F100.001
30
+ G0 X11.1 Y0 Z102
31
+ M0
32
+ """)
33
+
34
+ program.map_with_context.last.absolute?.should eq false
35
+ program.map_with_context {|cmd, ctx| ctx.position }.first.should eq [
36
+ [ 0, 0, 0 ],
37
+ [ 0, 0, 0 ],
38
+ [ 0, 0, 0 ],
39
+ [ 42, 13, 22.2 ],
40
+ [ 53.1, 13, 124.2 ]
41
+ ]
42
+ end
43
+
44
+ it 'should maintain the correct feedrate in map_with_context' do
45
+ program = GCoder::Parser.new.parse("""
46
+ G90
47
+ G0 X0 Y0 Z0 F140
48
+ G1 X42 Y13 Z22.2 F100.001
49
+ G0 X11.1 Y0 Z102
50
+ M0
51
+ """)
52
+
53
+ program.map_with_context {|cmd, ctx| ctx.feedrate }.first.should eq [ 0, 0, 140, 100.001, 100.001 ]
54
+ end
55
+
56
+ end
@@ -0,0 +1,54 @@
1
+ require 'rspec'
2
+ require 'spec_helper'
3
+
4
+ describe 'GCode parser' do
5
+
6
+ before do
7
+ @parser = GCoder::Parser.new
8
+ end
9
+
10
+ it 'should return a GCode program' do
11
+ @parser.parse("G0 X0 Y0 Z0 F1").should be_an_instance_of GCoder::GCode::Program
12
+ end
13
+
14
+ it 'should parse rapid motion GCode' do
15
+ cmd = @parser.parse("G0 X1 Y22.22 Z33.3 F12").first
16
+
17
+ cmd.should be_an_instance_of GCoder::GCode::MoveRapid
18
+ cmd.feedrate.should eq 12
19
+ cmd.position.should eq [ 1, 22.22, 33.3 ]
20
+ end
21
+
22
+ it 'should parse feedrate motion GCode' do
23
+ cmd = @parser.parse("G1 X1 Y22.22 Z33.3 F12").first
24
+
25
+ cmd.should be_an_instance_of GCoder::GCode::MoveByFeedrate
26
+ cmd.feedrate.should eq 12
27
+ cmd.position.should eq [ 1, 22.22, 33.3 ]
28
+ end
29
+
30
+ it 'should omit empty lines' do
31
+ prog = @parser.parse("""
32
+ G0 X1 Y2 Z3
33
+
34
+ M0
35
+ """)
36
+ prog.length.should eq 2
37
+ end
38
+
39
+ it 'should parse comments' do
40
+ comments = [
41
+ "Hello World, this is a comment",
42
+ "Let's try another comment"
43
+ ]
44
+
45
+ prog = @parser.parse(comments.map {|c| "(#{c})\n" }.join("\n"))
46
+
47
+ prog.length.should eq comments.length
48
+ prog.each_with_index do |cmd, idx|
49
+ cmd.should be_an_instance_of GCoder::GCode::Comment
50
+ cmd.text.should eq comments[idx]
51
+ end
52
+ end
53
+
54
+ end
@@ -0,0 +1,4 @@
1
+ $:.unshift File.join(File.dirname(__FILE__), '..', 'lib')
2
+
3
+ require 'gcoder'
4
+ require 'pry'
metadata ADDED
@@ -0,0 +1,98 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: g-coder
3
+ version: !ruby/object:Gem::Version
4
+ version: '0.1'
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - 32leaves
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2014-02-11 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: bundler
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: '1.5'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: '1.5'
30
+ - !ruby/object:Gem::Dependency
31
+ name: rake
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ description: GCoder is designed to make scripting GCode filters easy, and to work
47
+ with Opal to enable web-based GCode editors/viewers.
48
+ email:
49
+ - info@32leav.es
50
+ executables: []
51
+ extensions: []
52
+ extra_rdoc_files: []
53
+ files:
54
+ - .gitignore
55
+ - Gemfile
56
+ - LICENSE
57
+ - README.md
58
+ - Rakefile
59
+ - gcoder.gemspec
60
+ - lib/gcoder.rb
61
+ - lib/gcoder/dialects/default.rb
62
+ - lib/gcoder/gcode.rb
63
+ - lib/gcoder/parser.rb
64
+ - lib/gcoder/version.rb
65
+ - spec/default_dialect_spec.rb
66
+ - spec/gcode_program_spec.rb
67
+ - spec/parser_spec.rb
68
+ - spec/spec_helper.rb
69
+ homepage: ''
70
+ licenses:
71
+ - MIT
72
+ post_install_message:
73
+ rdoc_options: []
74
+ require_paths:
75
+ - lib
76
+ required_ruby_version: !ruby/object:Gem::Requirement
77
+ none: false
78
+ requirements:
79
+ - - ! '>='
80
+ - !ruby/object:Gem::Version
81
+ version: '0'
82
+ required_rubygems_version: !ruby/object:Gem::Requirement
83
+ none: false
84
+ requirements:
85
+ - - ! '>='
86
+ - !ruby/object:Gem::Version
87
+ version: '0'
88
+ requirements: []
89
+ rubyforge_project:
90
+ rubygems_version: 1.8.23
91
+ signing_key:
92
+ specification_version: 3
93
+ summary: GCoder is a Ruby library to deal with GCode in various flavours.
94
+ test_files:
95
+ - spec/default_dialect_spec.rb
96
+ - spec/gcode_program_spec.rb
97
+ - spec/parser_spec.rb
98
+ - spec/spec_helper.rb