lis 0.2.3 → 0.4.3

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,6 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.8.7
4
+ - 1.9.2
5
+ - 1.9.3
6
+ - 2.0.0
data/Gemfile CHANGED
@@ -1,2 +1,2 @@
1
- source :rubygems
1
+ source "https://rubygems.org"
2
2
  gemspec
@@ -13,7 +13,52 @@ available][spec])
13
13
  [spec]: http://www.google.com/search?q=dpc+lis+immulite+2000+filetype:pdf
14
14
 
15
15
 
16
+ ## Usage
17
+
18
+ * run the LIS server:
19
+
20
+ ```
21
+ $ gem install lis
22
+ $ lis help
23
+ $ lis -l /dev/ttyUSB0 -e http://worklist.example/lis server
24
+ ```
25
+
26
+ * now, whenever order requests arrive from the LIS hardware, lis2http will forward them to the specified HTTP endpoint:
27
+
28
+ ```
29
+ GET http://worklist.example/lis/{DEVICE_NAME}-{SPECIMEN_ID}
30
+ ```
31
+
32
+ * this should return basic patient information as well as test IDs for all pending requests:
33
+
34
+ ```
35
+ ---
36
+ id: '1234'
37
+ patient:
38
+ id: 98
39
+ last_name: Sierra
40
+ first_name: Rudolph
41
+ types:
42
+ - TSTID
43
+ - TSH
44
+ - FT3
45
+ - FT4
46
+ ```
47
+
48
+ * results are posted to the same URI as soon as they are received:
49
+
50
+ ```
51
+ POST http://worklist.example/lis/{DEVICE_NAME}-{SPECIMEN_ID}/{TEST_NAME}
52
+
53
+ ---
54
+ flags: N
55
+ result_timestamp: '1993-10-11T09:12:33+00:00'
56
+ status: F
57
+ test_name: TSTID
58
+ unit: mIU/mL
59
+ value: '8.2'
60
+ ```
16
61
 
17
62
  ## Copyright
18
63
 
19
- Copyright (c) 2010-2011 Levin Alexander. See LICENSE for details.
64
+ Copyright (c) 2010-2013 Levin Alexander. See LICENSE for details.
data/Rakefile CHANGED
@@ -7,9 +7,7 @@ require 'lis'
7
7
 
8
8
  require 'rake/testtask'
9
9
  Rake::TestTask.new(:test) do |test|
10
- test.libs << 'lib' << 'test'
11
- test.pattern = 'test/**/test_*.rb'
12
- test.verbose = true
10
+ test.libs << 'test'
13
11
  end
14
12
 
15
13
  require 'cucumber/rake/task'
data/bin/lis ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env ruby
2
+ require 'gli'
3
+
4
+ require 'lis'
5
+ require 'lis/cli'
6
+
7
+ exit LIS::CLI.run(ARGV.dup)
8
+
@@ -1,8 +1,4 @@
1
1
  Feature:
2
- In order to diagnose patients correctly
3
- As a doctor
4
- I want to be able to receive test results via LIS
5
-
6
2
  Scenario: LIS asking for pending requests
7
3
  Given LIS Interface listening for messages
8
4
  And the following requests are pending for DPC:
@@ -17,7 +13,7 @@ Feature:
17
13
  Then LIS should have sent test orders to client:
18
14
  """
19
15
  1H|\^&|||LIS||||8N1|DPC||P|1|
20
- 2P|1||||Müller^Rudolph||||||||
16
+ 2P|1|98||98|Müller^Rudolph||||||||
21
17
  3O|1|123ABC||^^^TSH
22
18
  4O|1|123ABC||^^^FT3
23
19
  5O|1|123ABC||^^^FT4
@@ -0,0 +1,6 @@
1
+ Feature: My bootstrapped app kinda works
2
+
3
+ Scenario: App just runs
4
+ When I get help for "lis"
5
+ Then the exit status should be 0
6
+
@@ -0,0 +1,6 @@
1
+ When /^I get help for "([^"]*)"$/ do |app_name|
2
+ @app_name = app_name
3
+ step %(I run `#{app_name} --help`)
4
+ end
5
+
6
+ # Add more step definitions here
@@ -1,16 +1,14 @@
1
1
  # encoding: UTF-8
2
2
 
3
- require 'mocha'
4
- require 'yaml'
3
+
5
4
 
6
5
 
7
6
  Given /^LIS Interface listening for messages$/ do
8
7
  @client, @r, @w = PacketIO::Test::MockServer.build
9
8
  @io = PacketIO::IOListener.new(@r, @w)
10
- @server = LIS::InterfaceServer.create(@io, "http://localhost/lis/")
9
+ @server = LIS::InterfaceServer.create(@io, "http://localhost/lis")
11
10
 
12
- stub_request(:post, /http:\/\/localhost\/lis\/result\/.*/).
13
- with(:body => /.*/, :headers => {'Accept'=>'*/*', 'Content-Type'=>'application/x-www-form-urlencoded'}).
11
+ stub_request(:post, /http:\/\/localhost\/lis\/.*?\/.*/).
14
12
  to_return(:status => 200, :body => "", :headers => {})
15
13
 
16
14
  @t = Thread.new do
@@ -36,7 +34,7 @@ end
36
34
  Then /^should have posted results:$/ do |table|
37
35
  table.hashes.each do |row|
38
36
  expected_body = ["test_name", "value", "unit", "status", "flags", "result_timestamp"].inject({}) { |h,k| h[k] = row[k]; h }
39
- assert_requested(:post, "http://localhost/lis/result/#{row["id"]}", :times => 1, :body => expected_body)
37
+ assert_requested(:post, "http://localhost/lis/#{row["id"]}/#{row["test_name"]}", :times => 1, :body => hash_including(expected_body))
40
38
  end
41
39
  end
42
40
 
@@ -53,16 +51,13 @@ Given /^the following requests are pending for (\w+):$/ do |device_name, table|
53
51
  table.hashes.each do |patient|
54
52
  body = { "patient" => { "last_name" => patient["last_name"],
55
53
  "first_name" => patient["first_name"],
56
- "id" => patient["patient_id"]},
54
+ "number" => patient["patient_id"]},
57
55
  "id" => patient["id"],
58
56
  "types" => patient["test_names"].strip.split(/\s+/) }
59
57
 
60
- stub_request(:get, "http://localhost/lis/find_requests/#{device_name}-#{patient["id"]}").
61
- with(:headers => {'Accept'=>'*/*'}).
58
+ stub_request(:get, "http://localhost/lis/#{device_name}-#{patient["id"]}").
62
59
  to_return(:status => 200, :body => body.to_yaml, :headers => {})
63
-
64
60
  end
65
-
66
61
  end
67
62
 
68
63
 
@@ -1,9 +1,16 @@
1
1
  $LOAD_PATH.unshift(File.dirname(__FILE__) + '/../../lib')
2
+
2
3
  require 'lis'
3
4
 
5
+ require 'mocha'
6
+ require 'yaml'
7
+ require 'aruba/cucumber'
8
+
4
9
  require 'packet_io/test/mock_server'
5
10
  require 'test/unit/assertions'
6
11
  require 'webmock/cucumber'
7
12
 
13
+ WebMock.disable_net_connect!
14
+
8
15
  World(Test::Unit::Assertions)
9
16
 
data/lib/lis.rb CHANGED
@@ -1,15 +1,16 @@
1
- $:.unshift File.dirname(__FILE__)
2
-
3
1
  require 'packet_io'
2
+ require 'yaml'
4
3
 
5
4
  require 'lis/version'
6
-
7
5
  require 'lis/messages.rb'
6
+ require 'lis/data'
7
+
8
8
  Dir[File.join(File.dirname(__FILE__), 'lis/messages/**/*.rb')].each { |f| require f }
9
9
 
10
10
  require 'lis/transfer/astm_e1394.rb'
11
11
  require 'lis/transfer/application_protocol.rb'
12
+ require 'lis/transfer/logging'
13
+ require 'lis/http_interface.rb'
12
14
 
13
- require 'lis/worklist_manager_interface.rb'
14
15
  require 'lis/interface_server.rb'
15
16
 
@@ -0,0 +1,47 @@
1
+ module LIS
2
+ module CLI
3
+ extend GLI::App
4
+ program_desc "LIS interface to Siemens Immulite 2000XPi or other similar analyzers"
5
+ version LIS::VERSION
6
+
7
+ flag ["config","c"], :default_value => File.join(ENV['HOME'],'.lis'),
8
+ :desc => "stores configuration and authentication data",
9
+ :arg_name => "FILE"
10
+
11
+ flag ["listen", "l"], :arg_name => "PORT", :desc => "which port to listen on", :default_value => "/dev/ttyUSB0"
12
+ flag ["endpoint", "e"], :arg_name => "URI", :desc => "HTTP endpoint", :default_value => "http://localhost/api/lis"
13
+ switch ["verbose", "v"], :desc => "Increase verbosity"
14
+
15
+ pre do |global_options,command,options,args|
16
+ $VERBOSE = global_options[:verbose]
17
+ true
18
+ end
19
+
20
+ desc "run the LIS server"
21
+ command "server" do |c|
22
+ c.action do |global_options,options,args|
23
+ port = global_options[:listen]
24
+ warn "configuring #{port}"
25
+ `stty -echo raw ospeed 9600 ispeed 9600 < #{port}`
26
+ warn "listening on: #{port}"
27
+ port = File.open(port, "w+")
28
+
29
+ LIS::InterfaceServer.listen(port, global_options[:endpoint]).run!
30
+ end
31
+ end
32
+
33
+ desc "load a list of test requests"
34
+ arg_name "DEVICE_NAME REQUEST_ID"
35
+ command "requests" do |c|
36
+ c.action do |global_options,options,args|
37
+
38
+ req = LIS::HTTPInterface.new(global_options[:endpoint]).load_requests(*args)
39
+ puts req.types
40
+ end
41
+
42
+
43
+ end
44
+
45
+
46
+ end
47
+ end
@@ -0,0 +1,45 @@
1
+ module LIS
2
+ module Data
3
+ class Request
4
+ def initialize(data={})
5
+ @data = data
6
+ end
7
+
8
+ def patient_id
9
+ @data["patient"]["number"]
10
+ end
11
+ def patient_last_name
12
+ @data["patient"]["last_name"]
13
+ end
14
+ def patient_first_name
15
+ @data["patient"]["first_name"]
16
+ end
17
+ def id
18
+ @data["id"]
19
+ end
20
+
21
+ def types
22
+ @data["types"]
23
+ end
24
+
25
+
26
+ def each_type
27
+ @data["types"].each do |t|
28
+ yield id, t
29
+ end
30
+ end
31
+
32
+ def to_hash
33
+ @data
34
+ end
35
+
36
+ def self.from_yaml(text, barcode)
37
+ data = YAML.load(text)
38
+ data["id"] = barcode
39
+
40
+ new(data)
41
+ end
42
+ end
43
+ end
44
+ end
45
+
@@ -0,0 +1,74 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'rest-client'
4
+
5
+ class LIS::HTTPInterface
6
+ def initialize(endpoint)
7
+ @endpoint = endpoint
8
+ end
9
+
10
+ # expects all pending requests for the given device and barcode
11
+ #
12
+ # { "id" => "1234",
13
+ # "patient" => { "id" => 98,
14
+ # "last_name" => "Sierra",
15
+ # "first_name" => "Rudolph" },
16
+ # "types" => [ "TSH", "FT3", "FT4" ] }
17
+ #
18
+ def load_requests(device_name, barcode)
19
+ begin
20
+ result = RestClient.get(uri(device_name, barcode))
21
+ data = LIS::Data::Request.from_yaml(result.body, barcode)
22
+ rescue Exception => e
23
+ puts e
24
+ puts e.backtrace
25
+ data = nil
26
+ end
27
+
28
+ warn "data: #{data.inspect}" if $VERBOSE
29
+
30
+ data
31
+ end
32
+
33
+
34
+ def set_request_status(device_name, data)
35
+ # uri = URI.join(@endpoint, "result_status/#{[device_name, data.id].join('-')}")
36
+ # Net::HTTP.post_form(uri, data.to_hash)
37
+ end
38
+
39
+ def send_result(device_name, order, result)
40
+ barcode = order.specimen_id
41
+
42
+ data = {
43
+ "test_name" => order.universal_test_id,
44
+ "value" => result.result_value,
45
+ "unit" => result.unit,
46
+ "status" => result.result_status,
47
+ "flags" => result.abnormal_flags,
48
+ "result_timestamp" => result.test_completed_at,
49
+ "raw" => result.raw_data
50
+ }
51
+
52
+ # FIXME: WTF: should not just catch everything
53
+ begin
54
+ res = RestClient.post(uri(device_name, barcode, order.universal_test_id), data)
55
+ rescue Exception => e
56
+ puts "EXCEPTION"
57
+ p e
58
+ end
59
+ end
60
+
61
+
62
+ private
63
+
64
+ def uri(device_name, barcode, test_name = nil)
65
+ id = [device_name, barcode].join("-")
66
+
67
+ s = [@endpoint, id, test_name].compact.join("/")
68
+ warn "uri: #{s}" if $VERBOSE
69
+
70
+ s
71
+ end
72
+
73
+ end
74
+
@@ -10,17 +10,21 @@ module LIS
10
10
  end
11
11
 
12
12
 
13
- def initialize(server, http_endpoint, protocol_stack = [LIS::Transfer::ASTM::E1394, LIS::Transfer::ApplicationProtocol])
13
+ def initialize(server, http_endpoint)
14
14
  @server = server
15
- protocol = protocol_stack.inject(server) { |i,klass| klass.new(i) }
16
- interface = WorklistManagerInterface.new(http_endpoint)
17
15
 
16
+ protocol = LIS::Transfer::ApplicationProtocol.new(LIS::Transfer::Logging.new(LIS::Transfer::ASTM::E1394.new(server)))
17
+ interface = HTTPInterface.new(http_endpoint)
18
18
 
19
19
  protocol.on_request do |device_name, barcode|
20
+ warn "loading requests" if $VERBOSE
20
21
  interface.load_requests(device_name, barcode)
21
22
  end
22
- protocol.on_result do |*args|
23
- interface.send_result(*args)
23
+ protocol.on_result do |device_name, patient, order, result|
24
+ interface.send_result(device_name, order, result)
25
+ end
26
+ protocol.on_request_sent do |device_name, data|
27
+ interface.set_request_status(device_name, data)
24
28
  end
25
29
  end
26
30
 
@@ -38,6 +38,10 @@ module LIS::Message
38
38
  has_field 12, :test_started_at, :type => :timestamp
39
39
  has_field 13, :test_completed_at, :type => :timestamp
40
40
 
41
+ def raw_data
42
+ to_message
43
+ end
44
+
41
45
  def universal_test_id
42
46
  universal_test_id_internal.gsub(/\^/,"")
43
47
  end
@@ -12,6 +12,10 @@ module LIS::Transfer
12
12
  @on_request_callback = block
13
13
  end
14
14
 
15
+ def on_request_sent(&block)
16
+ @on_request_sent_callback = block
17
+ end
18
+
15
19
  def received_header(message)
16
20
  @patient_information_requests ||= {} # delete the list of patients
17
21
  @device_name = message.sender_name
@@ -42,14 +46,16 @@ module LIS::Transfer
42
46
 
43
47
  def send_pending_requests
44
48
  sending_session(@patient_information_requests) do |patient_information|
45
- patient_information.each do |sequence_nr, data|
49
+ patient_information.each do |sequence_nr, request_data|
46
50
  write :message, LIS::Message::Patient.new(sequence_nr,
47
- data["patient"]["number"],
48
- data["patient"]["last_name"],
49
- data["patient"]["first_name"]).to_message
50
- data["types"].each do |request|
51
- write :message, LIS::Message::Order.new(sequence_nr, data["id"], request).to_message
51
+ request_data.patient_id,
52
+ request_data.patient_last_name,
53
+ request_data.patient_first_name).to_message
54
+ request_data.each_type do |id, request|
55
+ write :message, LIS::Message::Order.new(sequence_nr, id, request).to_message
52
56
  end
57
+
58
+ @on_request_sent_callback.call(@device_name, request_data) if @on_request_sent_callback
53
59
  end
54
60
  end
55
61
  @patient_information_requests = {}
@@ -71,7 +77,6 @@ module LIS::Transfer
71
77
  end
72
78
 
73
79
  def receive(type, message = nil)
74
- warn "[R] #{message}" if type == :message and $VERBOSE
75
80
  case type
76
81
  when :begin
77
82
  @last_patient = nil
@@ -8,7 +8,7 @@ module LIS::Transfer
8
8
  # splits a stream into lis packets and only lets packets through
9
9
  # that are inside a session delimited by ENQ .. EOT
10
10
  #
11
- # check the checksum and do acknowledgement of messages
11
+ # checks the checksum and does acknowledgement of messages
12
12
  #
13
13
  # forwards the following events:
14
14
  #
@@ -81,7 +81,7 @@ module LIS::Transfer
81
81
 
82
82
  frame_number, data, checksum = match[1 .. 3]
83
83
 
84
- expected_checksum = (frame_number + data).each_byte.inject(16) { |a,b| (a+b) % 0x100 }
84
+ expected_checksum = compute_checksum(frame_number + data)
85
85
  actual_checksum = checksum.to_i(16)
86
86
 
87
87
  raise "checksum mismatch: expected %03x got %03x" % [expected_checksum, actual_checksum] unless expected_checksum == actual_checksum
@@ -90,12 +90,16 @@ module LIS::Transfer
90
90
 
91
91
  def self.wrap_message(string, frame_number)
92
92
  frame_number = (frame_number % 8).to_s
93
- checksum = (frame_number + string).each_byte.inject(16) { |a,b| (a+b) % 0x100 }
93
+ checksum = compute_checksum(frame_number + string)
94
94
  checksum = checksum.to_s(16).upcase.rjust(2,"0")
95
95
 
96
96
  "\002#{frame_number}#{string}\015\003#{checksum}\015\012"
97
97
  end
98
98
 
99
+ def self.compute_checksum(str)
100
+ str.each_byte.inject(16) { |a,b| (a+b) % 0x100 }
101
+ end
102
+
99
103
 
100
104
  def received_message(message)
101
105
  return false unless @inside_transmission
@@ -0,0 +1,27 @@
1
+
2
+ module LIS::Transfer
3
+ class Logging < ::PacketIO::Base
4
+ def initialize(*args)
5
+ @verbose = $VERBOSE
6
+ super
7
+ end
8
+
9
+ def receive(type, message=nil)
10
+ output("<", type, message)
11
+ super
12
+ end
13
+
14
+ def write(type, message=nil)
15
+ output(">", type, message)
16
+ super
17
+ end
18
+
19
+
20
+ private
21
+
22
+ def output(direction, type, message)
23
+ warn [direction, type.to_s, message].join(" ") if @verbose
24
+ end
25
+ end
26
+ end
27
+
@@ -1,6 +1,6 @@
1
1
  # encoding: UTF-8
2
2
 
3
3
  module LIS
4
- VERSION = "0.2.3"
4
+ VERSION = "0.4.3"
5
5
  end
6
6
 
@@ -20,12 +20,16 @@ Gem::Specification.new do |s|
20
20
  s.require_paths = ["lib"]
21
21
  s.summary = %q{LIS interface to Siemens Immulite 2000XPi or other similar analyzers}
22
22
 
23
- s.add_dependency "packet_io", "~> 0.4.0"
23
+ s.add_dependency "packet_io", ">= 0.4.2"
24
+ s.add_dependency "rest-client"
25
+ s.add_dependency "rake"
26
+ s.add_dependency "gli", ">= 2.0.0.rc5"
24
27
 
25
- s.add_development_dependency("shoulda", "~> 2.11.3")
26
- s.add_development_dependency("mocha", "~> 0.9.12")
27
- s.add_development_dependency("yard", "~> 0.7.1")
28
- s.add_development_dependency("cucumber", "~> 0.10.3")
29
- s.add_development_dependency("webmock", "~> 1.6.4")
28
+ s.add_development_dependency("shoulda", ">= 3.1.0")
29
+ s.add_development_dependency("mocha", ">= 0.12.0")
30
+ s.add_development_dependency("yard")
31
+ s.add_development_dependency("cucumber", ">= 1.2.0")
32
+ s.add_development_dependency("webmock", ">= 1.8.7")
33
+ s.add_development_dependency('aruba')
30
34
  end
31
35
 
@@ -1,12 +1,15 @@
1
1
  require 'rubygems'
2
2
  require 'test/unit'
3
+ require 'webmock/test_unit'
3
4
  require 'shoulda'
4
- require 'mocha'
5
+ require 'mocha/setup'
5
6
 
6
7
  $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
7
8
  $LOAD_PATH.unshift(File.dirname(__FILE__))
8
9
  require 'lis'
9
10
 
11
+ WebMock.disable_net_connect!
12
+
10
13
  class Test::Unit::TestCase
11
14
  end
12
15
 
@@ -0,0 +1,61 @@
1
+ require 'helper'
2
+
3
+ class TestHTTPInterface < Test::Unit::TestCase
4
+
5
+ def setup
6
+ @interface = LIS::HTTPInterface.new("http://localhost/lis")
7
+ @device_name = "LIS1"
8
+ end
9
+
10
+
11
+ context "posting a result" do
12
+ setup do
13
+ @order = LIS::Message::Order.new(13, 12345, "TSTID")
14
+ @string = "R|1|^^^LH|8.2|mIU/mL|.7\.7^400\400|N|N|F||test|19931011091233|19931011091233|DPCCIRRUS"
15
+ @result = LIS::Message::Result.from_string(@string)
16
+ end
17
+
18
+ should "should post correct format to the HTTP endpoint" do
19
+ result_stub = stub_request(:post, "http://localhost/lis/LIS1-12345/TSTID").
20
+ with(:body => { "flags"=>"N",
21
+ "result_timestamp"=>"1993-10-11T09:12:33+00:00",
22
+ "status"=>"F",
23
+ "test_name"=>"TSTID",
24
+ "unit"=>"mIU/mL",
25
+ "value"=>"8.2",
26
+ "raw"=>@string}).
27
+ to_return(:status => 200, :body => "", :headers => {})
28
+
29
+ @interface.send_result(@device_name, @order, @result)
30
+ assert_requested(result_stub)
31
+ end
32
+ end
33
+
34
+ context "requesting test" do
35
+ setup do
36
+ @http_result = { "id" => "1234",
37
+ "patient" => { "number" => 98,
38
+ "last_name" => "Sierra",
39
+ "first_name" => "Rudolph" },
40
+ "types" => [ "TSH", "FT3", "FT4" ] }.to_yaml
41
+ end
42
+
43
+
44
+ should "return patient information and requests" do
45
+ stub_request( :get, "http://localhost/lis/LIS1-SOMETHING").to_return(:status => 301, :headers => { 'Location' => "http://localhost/lis/LIS1-1234" } )
46
+
47
+ result_stub = stub_request(:get, "http://localhost/lis/LIS1-1234")
48
+ result_stub.to_return( :status => 200, :body => @http_result, :headers => {})
49
+ data = @interface.load_requests(@device_name, "SOMETHING")
50
+
51
+ expected = { "id" => "SOMETHING",
52
+ "patient" => { "number" => 98,
53
+ "last_name" => "Sierra",
54
+ "first_name" => "Rudolph" },
55
+ "types" => [ "TSH", "FT3", "FT4" ] }
56
+
57
+ assert_equal expected, data.to_hash
58
+ end
59
+ end
60
+ end
61
+
@@ -70,4 +70,4 @@ class TestMessages < Test::Unit::TestCase
70
70
  end
71
71
  end
72
72
 
73
- end
73
+ end
metadata CHANGED
@@ -1,141 +1,201 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: lis
3
- version: !ruby/object:Gem::Version
4
- hash: 17
5
- prerelease: false
6
- segments:
7
- - 0
8
- - 2
9
- - 3
10
- version: 0.2.3
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.4.3
5
+ prerelease:
11
6
  platform: ruby
12
- authors:
7
+ authors:
13
8
  - Levin Alexander
14
9
  autorequire:
15
10
  bindir: bin
16
11
  cert_chain: []
17
-
18
- date: 2011-06-11 00:00:00 +02:00
19
- default_executable:
20
- dependencies:
21
- - !ruby/object:Gem::Dependency
12
+ date: 2013-03-05 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
22
15
  name: packet_io
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: 0.4.2
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: 0.4.2
30
+ - !ruby/object:Gem::Dependency
31
+ name: rest-client
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :runtime
23
39
  prerelease: false
24
- requirement: &id001 !ruby/object:Gem::Requirement
25
- none: false
26
- requirements:
27
- - - ~>
28
- - !ruby/object:Gem::Version
29
- hash: 15
30
- segments:
31
- - 0
32
- - 4
33
- - 0
34
- version: 0.4.0
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: rake
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
35
54
  type: :runtime
36
- version_requirements: *id001
37
- - !ruby/object:Gem::Dependency
38
- name: shoulda
39
55
  prerelease: false
40
- requirement: &id002 !ruby/object:Gem::Requirement
41
- none: false
42
- requirements:
43
- - - ~>
44
- - !ruby/object:Gem::Version
45
- hash: 37
46
- segments:
47
- - 2
48
- - 11
49
- - 3
50
- version: 2.11.3
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ - !ruby/object:Gem::Dependency
63
+ name: gli
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: 2.0.0.rc5
70
+ type: :runtime
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: 2.0.0.rc5
78
+ - !ruby/object:Gem::Dependency
79
+ name: shoulda
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ! '>='
84
+ - !ruby/object:Gem::Version
85
+ version: 3.1.0
51
86
  type: :development
52
- version_requirements: *id002
53
- - !ruby/object:Gem::Dependency
54
- name: mocha
55
87
  prerelease: false
56
- requirement: &id003 !ruby/object:Gem::Requirement
57
- none: false
58
- requirements:
59
- - - ~>
60
- - !ruby/object:Gem::Version
61
- hash: 35
62
- segments:
63
- - 0
64
- - 9
65
- - 12
66
- version: 0.9.12
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ! '>='
92
+ - !ruby/object:Gem::Version
93
+ version: 3.1.0
94
+ - !ruby/object:Gem::Dependency
95
+ name: mocha
96
+ requirement: !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ! '>='
100
+ - !ruby/object:Gem::Version
101
+ version: 0.12.0
67
102
  type: :development
68
- version_requirements: *id003
69
- - !ruby/object:Gem::Dependency
70
- name: yard
71
103
  prerelease: false
72
- requirement: &id004 !ruby/object:Gem::Requirement
73
- none: false
74
- requirements:
75
- - - ~>
76
- - !ruby/object:Gem::Version
77
- hash: 1
78
- segments:
79
- - 0
80
- - 7
81
- - 1
82
- version: 0.7.1
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ! '>='
108
+ - !ruby/object:Gem::Version
109
+ version: 0.12.0
110
+ - !ruby/object:Gem::Dependency
111
+ name: yard
112
+ requirement: !ruby/object:Gem::Requirement
113
+ none: false
114
+ requirements:
115
+ - - ! '>='
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
83
118
  type: :development
84
- version_requirements: *id004
85
- - !ruby/object:Gem::Dependency
86
- name: cucumber
87
119
  prerelease: false
88
- requirement: &id005 !ruby/object:Gem::Requirement
89
- none: false
90
- requirements:
91
- - - ~>
92
- - !ruby/object:Gem::Version
93
- hash: 49
94
- segments:
95
- - 0
96
- - 10
97
- - 3
98
- version: 0.10.3
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ none: false
122
+ requirements:
123
+ - - ! '>='
124
+ - !ruby/object:Gem::Version
125
+ version: '0'
126
+ - !ruby/object:Gem::Dependency
127
+ name: cucumber
128
+ requirement: !ruby/object:Gem::Requirement
129
+ none: false
130
+ requirements:
131
+ - - ! '>='
132
+ - !ruby/object:Gem::Version
133
+ version: 1.2.0
99
134
  type: :development
100
- version_requirements: *id005
101
- - !ruby/object:Gem::Dependency
135
+ prerelease: false
136
+ version_requirements: !ruby/object:Gem::Requirement
137
+ none: false
138
+ requirements:
139
+ - - ! '>='
140
+ - !ruby/object:Gem::Version
141
+ version: 1.2.0
142
+ - !ruby/object:Gem::Dependency
102
143
  name: webmock
144
+ requirement: !ruby/object:Gem::Requirement
145
+ none: false
146
+ requirements:
147
+ - - ! '>='
148
+ - !ruby/object:Gem::Version
149
+ version: 1.8.7
150
+ type: :development
103
151
  prerelease: false
104
- requirement: &id006 !ruby/object:Gem::Requirement
105
- none: false
106
- requirements:
107
- - - ~>
108
- - !ruby/object:Gem::Version
109
- hash: 7
110
- segments:
111
- - 1
112
- - 6
113
- - 4
114
- version: 1.6.4
152
+ version_requirements: !ruby/object:Gem::Requirement
153
+ none: false
154
+ requirements:
155
+ - - ! '>='
156
+ - !ruby/object:Gem::Version
157
+ version: 1.8.7
158
+ - !ruby/object:Gem::Dependency
159
+ name: aruba
160
+ requirement: !ruby/object:Gem::Requirement
161
+ none: false
162
+ requirements:
163
+ - - ! '>='
164
+ - !ruby/object:Gem::Version
165
+ version: '0'
115
166
  type: :development
116
- version_requirements: *id006
117
- description: ""
167
+ prerelease: false
168
+ version_requirements: !ruby/object:Gem::Requirement
169
+ none: false
170
+ requirements:
171
+ - - ! '>='
172
+ - !ruby/object:Gem::Version
173
+ version: '0'
174
+ description: ''
118
175
  email: mail@levinalex.net
119
- executables:
120
- - lis2http
176
+ executables:
177
+ - lis
121
178
  extensions: []
122
-
123
179
  extra_rdoc_files: []
124
-
125
- files:
180
+ files:
126
181
  - .gitignore
182
+ - .travis.yml
127
183
  - .yardopts
128
184
  - Gemfile
129
185
  - LICENSE
130
186
  - README.markdown
131
187
  - Rakefile
132
- - bin/lis2http
188
+ - bin/lis
133
189
  - features/communication basics.feature
134
190
  - features/lis.feature
191
+ - features/lis_cli.feature
192
+ - features/step_definitions/lis_cli_steps.rb
135
193
  - features/step_definitions/lis_steps.rb
136
194
  - features/support/env.rb
137
195
  - lib/lis.rb
138
- - lib/lis/commands/application.rb
196
+ - lib/lis/cli.rb
197
+ - lib/lis/data.rb
198
+ - lib/lis/http_interface.rb
139
199
  - lib/lis/interface_server.rb
140
200
  - lib/lis/messages.rb
141
201
  - lib/lis/messages/comment.rb
@@ -147,63 +207,60 @@ files:
147
207
  - lib/lis/messages/terminator.rb
148
208
  - lib/lis/transfer/application_protocol.rb
149
209
  - lib/lis/transfer/astm_e1394.rb
210
+ - lib/lis/transfer/logging.rb
150
211
  - lib/lis/version.rb
151
- - lib/lis/worklist_manager_interface.rb
152
212
  - lis.gemspec
153
213
  - test/helper.rb
154
- - test/lib/mock_server.rb
155
214
  - test/messages/test_header.rb
156
215
  - test/messages/test_order.rb
157
216
  - test/messages/test_patients.rb
158
217
  - test/messages/test_terminator.rb
159
218
  - test/test_application_protocol.rb
160
219
  - test/test_astm_e1394.rb
220
+ - test/test_http_interface.rb
161
221
  - test/test_messages.rb
162
- has_rdoc: true
163
222
  homepage: http://github.com/levinalex/lis
164
223
  licenses: []
165
-
166
224
  post_install_message:
167
- rdoc_options:
225
+ rdoc_options:
168
226
  - --charset=UTF-8
169
- require_paths:
227
+ require_paths:
170
228
  - lib
171
- required_ruby_version: !ruby/object:Gem::Requirement
229
+ required_ruby_version: !ruby/object:Gem::Requirement
172
230
  none: false
173
- requirements:
174
- - - ">="
175
- - !ruby/object:Gem::Version
176
- hash: 3
177
- segments:
231
+ requirements:
232
+ - - ! '>='
233
+ - !ruby/object:Gem::Version
234
+ version: '0'
235
+ segments:
178
236
  - 0
179
- version: "0"
180
- required_rubygems_version: !ruby/object:Gem::Requirement
237
+ hash: 4116448878207311103
238
+ required_rubygems_version: !ruby/object:Gem::Requirement
181
239
  none: false
182
- requirements:
183
- - - ">="
184
- - !ruby/object:Gem::Version
185
- hash: 3
186
- segments:
187
- - 0
188
- version: "0"
240
+ requirements:
241
+ - - ! '>='
242
+ - !ruby/object:Gem::Version
243
+ version: '0'
189
244
  requirements: []
190
-
191
245
  rubyforge_project:
192
- rubygems_version: 1.3.7
246
+ rubygems_version: 1.8.25
193
247
  signing_key:
194
248
  specification_version: 3
195
249
  summary: LIS interface to Siemens Immulite 2000XPi or other similar analyzers
196
- test_files:
250
+ test_files:
197
251
  - features/communication basics.feature
198
252
  - features/lis.feature
253
+ - features/lis_cli.feature
254
+ - features/step_definitions/lis_cli_steps.rb
199
255
  - features/step_definitions/lis_steps.rb
200
256
  - features/support/env.rb
201
257
  - test/helper.rb
202
- - test/lib/mock_server.rb
203
258
  - test/messages/test_header.rb
204
259
  - test/messages/test_order.rb
205
260
  - test/messages/test_patients.rb
206
261
  - test/messages/test_terminator.rb
207
262
  - test/test_application_protocol.rb
208
263
  - test/test_astm_e1394.rb
264
+ - test/test_http_interface.rb
209
265
  - test/test_messages.rb
266
+ has_rdoc:
@@ -1,6 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- require 'lis'
4
- require 'lis/commands/application.rb'
5
-
6
- LIS::Application.new(ARGV).run!
@@ -1,57 +0,0 @@
1
- # encoding: UTF-8
2
-
3
- require 'optparse'
4
-
5
- module LIS
6
- class Options < Hash
7
- attr_reader :opts
8
-
9
- def initialize(args)
10
- super()
11
-
12
- default_options = { :port => "/dev/ttyUSB0", :uri => "http://localhost/lis/" }
13
- self.merge!(default_options)
14
-
15
- @opts = OptionParser.new do |o|
16
- appname = File.basename($0)
17
- o.banner = "Usage: #{appname} [options]"
18
-
19
- o.on('-l, --listen PORT', 'which port to listen on (default: "/dev/ttyUSB0")') do |port|
20
- self[:port] = port
21
- end
22
- o.on('-e, --endpoint URI', 'HTTP endpoint (default: "http://localhost/lis/")') do |endpoint|
23
- self[:uri] = endpoint
24
- end
25
- o.on("-v", "--[no-]verbose", "Run verbosely") do |v|
26
- $VERBOSE = v
27
- self[:verbose] = v
28
- end
29
- end
30
-
31
- begin
32
- @opts.parse!(args)
33
- self[:project_name] = args.shift
34
- rescue OptionParser::ParseError => e
35
- self[:invalid_argument] = e.message
36
- end
37
- end
38
- end
39
-
40
- class Application
41
- def initialize(opts)
42
- @options = Options.new(opts)
43
-
44
- if @options[:invalid_argument]
45
- warn @options.opts
46
- exit 1
47
- end
48
- end
49
-
50
- def run!
51
- warn "listening on: #{@options[:port]}"
52
- port = File.open(@options[:port], "w+")
53
- LIS::InterfaceServer.listen(port, @options[:uri]).run!
54
- end
55
- end
56
-
57
- end
@@ -1,69 +0,0 @@
1
- # encoding: UTF-8
2
-
3
- require 'net/http'
4
- require 'yaml'
5
-
6
- class WorklistManagerInterface
7
- def initialize(endpoint)
8
- @endpoint = endpoint
9
- end
10
-
11
- # expects all pending requests for the given device and barcode
12
- #
13
- # { "id" => "1234",
14
- # "patient" => { "number" => 98,
15
- # "last_name" => "Sierra",
16
- # "first_name" => "Rudolph" },
17
- # "types" => [ "TSH", "FT3", "FT4" ] }
18
- #
19
- #
20
- def load_requests(device_name, barcode)
21
- begin
22
- uri = URI.join(@endpoint,"find_requests/#{[device_name, barcode].join('-')}")
23
- result = fetch_with_redirect(uri.to_s)
24
- data = YAML.load(result.body)
25
- data["id"] = barcode
26
- rescue Exception => e
27
- puts e
28
- puts e.backtrace
29
- data = nil
30
- end
31
-
32
- data
33
- end
34
-
35
- def send_result(device_name, patient, order, result)
36
- barcode = order.specimen_id
37
- data = {
38
- "test_name" => order.universal_test_id,
39
- "value" => result.result_value,
40
- "unit" => result.unit,
41
- "status" => result.result_status,
42
- "flags" => result.abnormal_flags,
43
- "result_timestamp" => result.test_completed_at
44
- }
45
-
46
- # FIXME: WTF: should not just catch everything
47
- begin
48
- res = Net::HTTP.post_form(URI.join(@endpoint, "result/#{[device_name, barcode].join('-')}"), data.to_hash)
49
- rescue Exception => e
50
- puts "EXCEPTION"
51
- p e
52
- end
53
- end
54
-
55
-
56
- private
57
-
58
- def fetch_with_redirect(uri_str, limit = 10)
59
- raise ArgumentError, 'too many HTTP redirects' if limit == 0
60
-
61
- response = Net::HTTP.get_response(URI.parse(uri_str))
62
- case response
63
- when Net::HTTPSuccess then response
64
- when Net::HTTPRedirection then fetch_with_redirect(response['location'], limit - 1)
65
- else
66
- response.error!
67
- end
68
- end
69
- end
@@ -1,50 +0,0 @@
1
- module Mock
2
- end
3
-
4
- class Mock::Server
5
- def initialize(read, write)
6
- @read, @write = read, write
7
- @queue = Queue.new
8
- @thread = Thread.new do
9
- parse_commands
10
- end
11
- end
12
-
13
- def write(string)
14
- @queue.push [:write, string]
15
- self
16
- end
17
-
18
- def read_all
19
- @read.readpartial(4096)
20
- end
21
-
22
- def wait(seconds = 0.02)
23
- @queue.push [:wait, seconds]
24
- self
25
- end
26
-
27
- def eof
28
- @queue.push [:close]
29
- end
30
-
31
-
32
- private
33
-
34
- def parse_commands
35
- loop do
36
- action, data = @queue.pop
37
-
38
- case action
39
- when :close
40
- @write.close
41
- break
42
- when :write
43
- @write.write(data)
44
- @write.flush
45
- when :wait
46
- sleep data
47
- end
48
- end
49
- end
50
- end