FLOWer interpreter on Ruby

Usage: flower.rb [<] flower.json
※flower.jsonはダウンロードしたzipを展開すると取り出せます。

本家FLOWerのジョブの3割ほどをカバーしています。
挙動については私の類推です。
条件分岐はドキュメントがないため実装できませんでした。。

複数のジョブから一度に値を受け取った時は先に生成されたジョブから受け取った値を先に使用するという挙動は再現出来ているはずです。

```rb:flower.rb
#!/usr/bin/ruby
require 'json'

#FLOWer Job parent
class FLOWerJob
	def initialize(jobs,inputports,constant,outputports)
		@jobs=jobs # fixme
		@queue=Hash.new{|h,k|h[k]=[]}
		@inputports=inputports
		@constant=constant
		@outputports=outputports
		@input={}
		@constant.each{|k,v|
			@input[k]=v
		}
	end
	def send_value(port,value)
		@queue[port]<< value
	end
	def accept_value
		@queue.each{|k,v|
			if @input[k]==nil && v.size>0
				@input[k]=v.shift
			end
		}
	end
	def query
		return if @inputports.any?{|e|@input[e]==nil}
		query2
		@inputports.each{|e|
			@input[e]=nil if !@constant.has_key?(e)
		}
	end
end

#FLOWer Jobs
#core
class FLOWerJob_core_Through <FLOWerJob
	def query2
		value=@input['input']
		@outputports['output'].each{|job,port|
			@jobs[job].send_value(port,value)
		}
	end
end
class FLOWerJob_core_Add <FLOWerJob
	def query2
		value=@input['input1']+@input['input2']
		@outputports['output'].each{|job,port|
			@jobs[job].send_value(port,value)
		}
	end
end
class FLOWerJob_core_Times <FLOWerJob
	def query2
		value=@input['input1']*@input['input2']
		@outputports['output'].each{|job,port|
			@jobs[job].send_value(port,value)
		}
	end
end
class FLOWerJob_core_And <FLOWerJob
	def query2
		value=@input['input1']&@input['input2']
		@outputports['output'].each{|job,port|
			@jobs[job].send_value(port,value)
		}
	end
end
class FLOWerJob_core_Or <FLOWerJob
	def query2
		value=@input['input1']|@input['input2']
		@outputports['output'].each{|job,port|
			@jobs[job].send_value(port,value)
		}
	end
end
class FLOWerJob_core_Transistor <FLOWerJob
	def query2
		value=@input['emitter']
		@outputports['collector'].each{|job,port|
			@jobs[job].send_value(port,value)
		}
	end
end
#number
class FLOWerJob_number_C0 <FLOWerJob
	def query2
		value=0
		@outputports['0'].each{|job,port|
			@jobs[job].send_value(port,value)
		}
	end
end
class FLOWerJob_number_C1 <FLOWerJob
	def query2
		value=1
		@outputports['1'].each{|job,port|
			@jobs[job].send_value(port,value)
		}
	end
end
class FLOWerJob_number_C2 <FLOWerJob
	def query2
		value=2
		@outputports['2'].each{|job,port|
			@jobs[job].send_value(port,value)
		}
	end
end
class FLOWerJob_number_C3 <FLOWerJob
	def query2
		value=3
		@outputports['3'].each{|job,port|
			@jobs[job].send_value(port,value)
		}
	end
end
class FLOWerJob_number_C4 <FLOWerJob
	def query2
		value=4
		@outputports['4'].each{|job,port|
			@jobs[job].send_value(port,value)
		}
	end
end
class FLOWerJob_number_C5 <FLOWerJob
	def query2
		value=5
		@outputports['5'].each{|job,port|
			@jobs[job].send_value(port,value)
		}
	end
end
class FLOWerJob_number_C6 <FLOWerJob
	def query2
		value=6
		@outputports['6'].each{|job,port|
			@jobs[job].send_value(port,value)
		}
	end
end
class FLOWerJob_number_C7 <FLOWerJob
	def query2
		value=7
		@outputports['7'].each{|job,port|
			@jobs[job].send_value(port,value)
		}
	end
end
class FLOWerJob_number_C8 <FLOWerJob
	def query2
		value=8
		@outputports['8'].each{|job,port|
			@jobs[job].send_value(port,value)
		}
	end
end
class FLOWerJob_number_C9 <FLOWerJob
	def query2
		value=9
		@outputports['9'].each{|job,port|
			@jobs[job].send_value(port,value)
		}
	end
end
#math
class FLOWerJob_math_Abs <FLOWerJob
	def query2
		value=@input['input'].abs
		@outputports['output'].each{|job,port|
			@jobs[job].send_value(port,value)
		}
	end
end
class FLOWerJob_math_Max <FLOWerJob
	def query2
		value=[@input['a'],@input['b']].max
		@outputports['output'].each{|job,port|
			@jobs[job].send_value(port,value)
		}
	end
end
class FLOWerJob_math_Max <FLOWerJob
	def query2
		value=[@input['a'],@input['b']].min
		@outputports['output'].each{|job,port|
			@jobs[job].send_value(port,value)
		}
	end
end
#system
class FLOWerJob_system_Speed <FLOWerJob
	def query2
		value=@input['speed']
		# do nothing here
		@outputports['output'].each{|job,port|
			@jobs[job].send_value(port,value)
		}
	end
end
class FLOWerJob_system_Print <FLOWerJob
	def query2
		value=@input['input']
		print value.to_s+', '
		@outputports['output'].each{|job,port|
			@jobs[job].send_value(port,value)
		}
	end
end
class FLOWerJob_system_Scan <FLOWerJob
	def query2
		#value=@input['input']
		print 'input> '
		value=gets.to_i
		@outputports['output'].each{|job,port|
			@jobs[job].send_value(port,value)
		}
	end
end
#snapsvg
#snapelement
#map
#string
#array

#flower.json runner
class FLOWer
	def initialize(json_str)
		json=JSON.parse(json_str)
		@jobs={}
		json['diagram']['jobs'].each{|e|
			id=e['id']
			constant={}
			inputports=[]
			e['inputports'].each{|f|
				inputports<<f['name']
				if f['constant']
					constant[f['name']]=f['constant']['value']
				end
			}
			if e['ref']
				ref=e['ref']
			else
				ref='core.Through'
				inputports=['input']
				@entry=id
			end
			outputports={}
			e['outputports'].map{|f|
				outputports[f['name']]=f['connections'].map{|e|e.split('.')}
			}
			#If NameError is thrown here, that means the job is not implemented yet.
			@jobs[id]=Object.const_get('FLOWerJob_'+ref.gsub('.','_')).new(@jobs,inputports,constant,outputports)
		}
	end
	def run
		@jobs[@entry].send_value('input',0)
		@jobs[@entry].accept_value
		loop{
			@jobs.each{|k,v|
				v.query
			}
			@jobs.each{|k,v|
				v.accept_value
			}
		}
	end
end
FLOWer.new($<.read).run
```