multi_movingsign 0.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.
Files changed (53) hide show
  1. data/.gitignore +21 -0
  2. data/.rspec +2 -0
  3. data/.travis.yml +9 -0
  4. data/.yardopts +1 -0
  5. data/CHANGELOG.md +17 -0
  6. data/Gemfile +4 -0
  7. data/LICENSE.txt +22 -0
  8. data/PAGE_DEFINITION.md +115 -0
  9. data/README.md +133 -0
  10. data/Rakefile +1 -0
  11. data/bin/multi_movingsign +5 -0
  12. data/example.jpg +0 -0
  13. data/fonts/7-row-normal.png +0 -0
  14. data/fonts/README.md +1 -0
  15. data/lib/multi_movingsign.rb +9 -0
  16. data/lib/multi_movingsign/cli.rb +81 -0
  17. data/lib/multi_movingsign/errors.rb +10 -0
  18. data/lib/multi_movingsign/page_renderer.rb +223 -0
  19. data/lib/multi_movingsign/server.rb +317 -0
  20. data/lib/multi_movingsign/settings.rb +55 -0
  21. data/lib/multi_movingsign/sign.rb +37 -0
  22. data/lib/multi_movingsign/signs.rb +39 -0
  23. data/lib/multi_movingsign/testrc_loader.rb +17 -0
  24. data/lib/multi_movingsign/version.rb +3 -0
  25. data/multi_movingsign.gemspec +31 -0
  26. data/spec/cli_spec.rb +166 -0
  27. data/spec/noop_movingsign_sign.rb +47 -0
  28. data/spec/noop_movingsign_sign.yml +7 -0
  29. data/spec/page_renderer/example_1/1.yml +16 -0
  30. data/spec/page_renderer/example_1/2.yml +28 -0
  31. data/spec/page_renderer/example_1/4.yml +44 -0
  32. data/spec/page_renderer/example_1/5.json +10 -0
  33. data/spec/page_renderer/example_1/example_spec.rb +23 -0
  34. data/spec/page_renderer/example_1/page.yml +27 -0
  35. data/spec/page_renderer/example_2/1.yml +7 -0
  36. data/spec/page_renderer/example_2/2.yml +8 -0
  37. data/spec/page_renderer/example_2/4.json +9 -0
  38. data/spec/page_renderer/example_2/example_spec.rb +24 -0
  39. data/spec/page_renderer/example_2/page.yml +7 -0
  40. data/spec/page_renderer/example_3/1.yml +9 -0
  41. data/spec/page_renderer/example_3/3.yml +14 -0
  42. data/spec/page_renderer/example_3/example_spec.rb +22 -0
  43. data/spec/page_renderer/example_3/page.yml +12 -0
  44. data/spec/page_renderer/example_4/2.yml +12 -0
  45. data/spec/page_renderer/example_4/4.json +9 -0
  46. data/spec/page_renderer/example_4/example_spec.rb +24 -0
  47. data/spec/page_renderer/example_4/page.yml +12 -0
  48. data/spec/settings_1.yml +3 -0
  49. data/spec/settings_spec.rb +36 -0
  50. data/spec/spec_helper.rb +36 -0
  51. data/spec/support/doubles_support.rb +26 -0
  52. data/spec/support/executable_support.rb +112 -0
  53. metadata +244 -0
@@ -0,0 +1,44 @@
1
+ #---------
2
+ #Top Drinkers
3
+ #1. mikey
4
+ #2. capn
5
+ #3. eric
6
+ #---------
7
+ #Top Drinkers
8
+ #1. 445 pints
9
+ #2. 183 pints
10
+ #3. 122 pints
11
+ #---------
12
+ #Top Drinkers
13
+ #4. whitey
14
+ #5. justin
15
+ #6. scarfjerk
16
+ #---------
17
+ #Top Drinkers
18
+ #4. 114 pints
19
+ #5. 110 pints
20
+ #6. 109 pints
21
+ #---------
22
+ ---
23
+ lines: 4
24
+ signs:
25
+ - content: |-
26
+ Top Drinkers
27
+ Top Drinkers
28
+ Top Drinkers
29
+ Top Drinkers
30
+ - content: |-
31
+ 1. mikey
32
+ 1. 445 pints
33
+ 4. whitey
34
+ 4. 114 pints
35
+ - content: |-
36
+ 2. capn
37
+ 2. 183 pints
38
+ 5. justin
39
+ 5. 110 pints
40
+ - content: |-
41
+ 3. eric
42
+ 3. 122 pints
43
+ 6. scarfjerk
44
+ 6. 109 pints
@@ -0,0 +1,10 @@
1
+ {
2
+ "lines": 4,
3
+ "signs": [
4
+ { "content": "Top Drinkers\nTop Drinkers\nTop Drinkers\nTop Drinkers" },
5
+ { "content": "1. mikey\n1. 445 pints\n5. justin\n5. 110 pints" },
6
+ { "content": "2. capn\n2. 183 pints\n6. scarfjerk\n6. 109 pints" },
7
+ { "content": "3. eric\n3. 122 pints\n \n " },
8
+ { "content": "4. whitey\n4. 114 pints\n \n " }
9
+ ]
10
+ }
@@ -0,0 +1,23 @@
1
+ require 'spec_helper'
2
+ require 'yaml'
3
+ require 'json'
4
+
5
+ describe "PageRenderer - Example 1" do
6
+
7
+ [1, 2, 4, 5].each do |screens|
8
+ describe "#{screens} screen(s)" do
9
+ it "Renders as Expected" do
10
+ page = YAML.load(File.read(File.join(File.dirname(__FILE__), 'page.yml')))
11
+
12
+ expected = nil
13
+ if File.exists?(path = File.join(File.dirname(__FILE__), "#{screens}.yml"))
14
+ expected = YAML.load(File.read(path))
15
+ else
16
+ expected = JSON.load(File.read(File.join(File.dirname(__FILE__), "#{screens}.json")))
17
+ end
18
+
19
+ expect(MultiMovingsign::PageRenderer.new.render(page, :count => screens)).to eq(expected)
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,27 @@
1
+ ---
2
+ title: Top Drinkers
3
+ lines:
4
+ - prefix: '1. '
5
+ content:
6
+ - mikey
7
+ - 445 pints
8
+ - prefix: '2. '
9
+ content:
10
+ - capn
11
+ - 183 pints
12
+ - prefix: '3. '
13
+ content:
14
+ - eric
15
+ - 122 pints
16
+ - prefix: '4. '
17
+ content:
18
+ - whitey
19
+ - 114 pints
20
+ - prefix: '5. '
21
+ content:
22
+ - justin
23
+ - 110 pints
24
+ - prefix: '6. '
25
+ content:
26
+ - scarfjerk
27
+ - 109 pints
@@ -0,0 +1,7 @@
1
+ lines: 3
2
+ signs:
3
+ - content: |-
4
+ Top Drinkers
5
+ 1. mikey
6
+ 1. 445 pints
7
+
@@ -0,0 +1,8 @@
1
+ lines: 2
2
+ signs:
3
+ - content: |-
4
+ Top Drinkers
5
+ Top Drinkers
6
+ - content: |-
7
+ 1. mikey
8
+ 1. 445 pints
@@ -0,0 +1,9 @@
1
+ {
2
+ "lines": 2,
3
+ "signs": [
4
+ { "content": "Top Drinkers\nTop Drinkers" },
5
+ { "content": "1. mikey\n1. 445 pints" },
6
+ { "content": " \n " },
7
+ { "content": " \n " }
8
+ ]
9
+ }
@@ -0,0 +1,24 @@
1
+ require 'spec_helper'
2
+ require 'yaml'
3
+ require 'json'
4
+
5
+ describe "PageRenderer - Example 2" do
6
+
7
+ [1, 2, 4].each do |screens|
8
+ describe "#{screens} screen(s)" do
9
+ it "Renders as Expected" do
10
+ page = YAML.load(File.read(File.join(File.dirname(__FILE__), 'page.yml')))
11
+
12
+ expected = nil
13
+ if File.exists?(path = File.join(File.dirname(__FILE__), "#{screens}.yml"))
14
+ expected = YAML.load(File.read(path))
15
+ else
16
+ expected = JSON.load(File.read(File.join(File.dirname(__FILE__), "#{screens}.json")))
17
+ end
18
+
19
+
20
+ expect(MultiMovingsign::PageRenderer.new.render(page, :count => screens)).to eq(expected)
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,7 @@
1
+ ---
2
+ title: Top Drinkers
3
+ lines:
4
+ - prefix: '1. '
5
+ content:
6
+ - mikey
7
+ - 445 pints
@@ -0,0 +1,9 @@
1
+ lines: 6
2
+ signs:
3
+ - content: |-
4
+ On Tap
5
+ Stone IPA
6
+ 7.94 Pints
7
+ Drake's 1500
8
+ Pale Ale
9
+ 0 Pints
@@ -0,0 +1,14 @@
1
+ lines: 3
2
+ signs:
3
+ - content: |-
4
+ On Tap
5
+ On Tap
6
+ On Tap
7
+ - content: |-
8
+ Stone IPA
9
+ Stone IPA
10
+ 7.94 Pints
11
+ - content: |-
12
+ Drake's 1500
13
+ Pale Ale
14
+ 0 Pints
@@ -0,0 +1,22 @@
1
+ require 'spec_helper'
2
+ require 'yaml'
3
+ require 'json'
4
+
5
+ describe "PageRenderer - Example 3" do
6
+ [1, 3].each do |screens|
7
+ describe "#{screens} screen(s)" do
8
+ it "Renders as Expected" do
9
+ page = YAML.load(File.read(File.join(File.dirname(__FILE__), 'page.yml')))
10
+
11
+ expected = nil
12
+ if File.exists?(path = File.join(File.dirname(__FILE__), "#{screens}.yml"))
13
+ expected = YAML.load(File.read(path))
14
+ else
15
+ expected = JSON.load(File.read(File.join(File.dirname(__FILE__), "#{screens}.json")))
16
+ end
17
+
18
+ expect(MultiMovingsign::PageRenderer.new.render(page, :count => screens)).to eq(expected)
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,12 @@
1
+ # Line segment longer than displayable
2
+ # Missing prefix line
3
+ ---
4
+ title: On Tap
5
+ lines:
6
+ - segments:
7
+ - Stone IPA
8
+ - 7.94 Pints
9
+ - segments:
10
+ - Drake's 1500 Pale Ale
11
+ - 0 Pints
12
+
@@ -0,0 +1,12 @@
1
+ lines: 4
2
+ signs:
3
+ - content: |-
4
+ ALERT ALERT
5
+ ALERT ALERT
6
+ ALERT ALERT
7
+ ALERT ALERT
8
+ - content: |-
9
+ ALERT 1
10
+ ALERT 2
11
+ ALERT 3
12
+ ALERT 4
@@ -0,0 +1,9 @@
1
+ {
2
+ "lines": 2,
3
+ "signs": [
4
+ { "content": "ALERT ALERT\nALERT ALERT" },
5
+ { "content": "ALERT 1\nALERT 4" },
6
+ { "content": "ALERT 2\n " },
7
+ { "content": "ALERT 3\n " }
8
+ ]
9
+ }
@@ -0,0 +1,24 @@
1
+ require 'spec_helper'
2
+ require 'yaml'
3
+ require 'json'
4
+
5
+ describe "PageRenderer - Example 3" do
6
+ [2,4].each do |screens|
7
+ describe "#{screens} screen(s)" do
8
+ it "Renders as Expected" do
9
+ page = nil
10
+
11
+ page = YAML.load(File.read(File.join(File.dirname(__FILE__), 'page.yml')))
12
+
13
+ expected = nil
14
+ if File.exists?(path = File.join(File.dirname(__FILE__), "#{screens}.yml"))
15
+ expected = YAML.load(File.read(path))
16
+ else
17
+ expected = JSON.load(File.read(File.join(File.dirname(__FILE__), "#{screens}.json")))
18
+ end
19
+
20
+ expect(MultiMovingsign::PageRenderer.new.render(page, :count => screens)).to eq(expected)
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,12 @@
1
+ ---
2
+ title: ALERT ALERT
3
+ lines:
4
+ - content:
5
+ - ALERT 1
6
+ - content:
7
+ - ALERT 2
8
+ - content:
9
+ - ALERT 3
10
+ - content:
11
+ - ALERT 4
12
+
@@ -0,0 +1,3 @@
1
+ ---
2
+ signs:
3
+ - path: /dev/ttyUSB0
@@ -0,0 +1,36 @@
1
+ require 'spec_helper'
2
+ require 'tempfile'
3
+
4
+ describe MultiMovingsign::Settings do
5
+ let(:tempfile) { Tempfile.new(['spec_settings', '.yml']) }
6
+
7
+ describe "Empty Settings File" do
8
+ subject { described_class.load (tempfile.path) }
9
+
10
+ it "#signs returns []" do
11
+ expect(subject.signs.length).to eq 0
12
+ end
13
+
14
+ it "#signs? returns false" do
15
+ expect(subject.signs?).to be_false
16
+ end
17
+ end
18
+
19
+ describe "Example Settings File - 1" do
20
+ subject { described_class.load(File.join(File.dirname(__FILE__), 'settings_1.yml'))}
21
+
22
+ it "#signs? returns true" do
23
+ expect(subject.signs?).to be_true
24
+ end
25
+
26
+ it "#signs.length == 1" do
27
+ expect(subject.signs.length).to eq 1
28
+ end
29
+
30
+ it "#signs contains path '/dev/ttyUSB0'" do
31
+ paths = subject.signs.map { |s| s.path }
32
+ expect(paths.include?('/dev/ttyUSB0')).to be_true
33
+ end
34
+
35
+ end
36
+ end
@@ -0,0 +1,36 @@
1
+ require 'multi_movingsign'
2
+ require 'support/executable_support'
3
+ require 'support/doubles_support'
4
+ require 'logger'
5
+
6
+ ruby_version = "#{RUBY_VERSION}-p#{RUBY_PATCHLEVEL}"
7
+ puts "Ruby Version: #{ruby_version}"
8
+
9
+ # Setup logging
10
+ rspec_log_path = "rspec.log"
11
+ RSPEC_LOGGER = Logger.new rspec_log_path
12
+
13
+ puts "Logging to #{rspec_log_path}"
14
+ RSPEC_LOGGER.info "Starting #{Time.now}"
15
+ RSPEC_LOGGER.info "Ruby Version: #{ruby_version}"
16
+
17
+ # This file was generated by the `rspec --init` command. Conventionally, all
18
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
19
+ # Require this file using `require "spec_helper"` to ensure that it is only
20
+ # loaded once.
21
+ #
22
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
23
+ RSpec.configure do |config|
24
+ config.treat_symbols_as_metadata_keys_with_true_values = true
25
+ config.run_all_when_everything_filtered = true
26
+ config.filter_run :focus
27
+
28
+ # Run specs in random order to surface order dependencies. If you find an
29
+ # order dependency and want to debug it, you can fix the order by providing
30
+ # the seed, which is printed after each run.
31
+ # --seed 1234
32
+ config.order = 'random'
33
+
34
+ config.include ExecutableHelpers
35
+ config.include MultiMoviginsignDoubles
36
+ end
@@ -0,0 +1,26 @@
1
+ module MultiMoviginsignDoubles
2
+ # Overrides MovingsignApi::Sign recording all calls to it's methods (for testing/validation)
3
+ def double_movingsign_sign
4
+ MovingsignApi::Sign.class_exec do
5
+ @@mutex = Mutex.new
6
+
7
+ class << self
8
+ attr_accessor :calls
9
+ end
10
+
11
+ (MovingsignApi::Sign.public_instance_methods.to_a - Object.public_instance_methods.to_a - [:device_path]).each do |method|
12
+ define_method(method) do |*args|
13
+ @@mutex.synchronize do
14
+ self.calls << [self.device_path, method, args]
15
+ end
16
+ end
17
+ end
18
+
19
+ def calls
20
+ self.class.calls
21
+ end
22
+ end
23
+
24
+ MovingsignApi::Sign.calls = []
25
+ end
26
+ end
@@ -0,0 +1,112 @@
1
+ require 'tempfile'
2
+ require 'hashie/mash'
3
+
4
+ module ExecutableHelpers
5
+ # Executes a given command string, collecting both stdout and stderr, along with the exit status.
6
+ # @return [ExecutationResult] container of the execution results
7
+ def execute(command)
8
+ out_path = File.join(Dir.mktmpdir('execute-'), 'stdout.log')
9
+ out_file = File.open(out_path, 'w')
10
+
11
+ pid = Kernel.spawn(command, [:out, :err] => out_file.fileno, :in => :close)
12
+ RSPEC_LOGGER.info "[#{pid}] Executed '#{command}' > #{out_file.path}"
13
+ Process.waitpid(pid)
14
+
15
+ out_file.flush
16
+ out_file.close
17
+
18
+ out = File.read out_file.path
19
+
20
+ result = ExecutationResult.new
21
+ result.status = $?
22
+ result.stdout = out
23
+
24
+ result
25
+ end
26
+
27
+ # This never really worked well for testing. Keeping for now.
28
+ ## Executes a given block in this procress
29
+ #def execute_in_process(&block)
30
+ # exit_status = 1
31
+ # stdout = ""
32
+ #
33
+ # stdout = capture do
34
+ # begin
35
+ # begin
36
+ # yield
37
+ # rescue ScriptError => e
38
+ # report_raise e
39
+ # exit 1
40
+ # rescue SignalException => e
41
+ # report_raise e
42
+ # exit 1
43
+ # rescue StandardError => e
44
+ # report_raise e
45
+ # exit 1
46
+ # end
47
+ # rescue SystemExit => e
48
+ # exit_status = e.status
49
+ # else
50
+ # exit_status = 0
51
+ # end
52
+ # end
53
+ #
54
+ # status_double = Object.new
55
+ # status_double.instance_exec(exit_status) do |status|
56
+ # @exit_status = status
57
+ #
58
+ # def success?
59
+ # @exit_status == 0
60
+ # end
61
+ #
62
+ # def exitstatus
63
+ # @exit_status
64
+ # end
65
+ # end
66
+ #
67
+ # result = ExecutationResult.new
68
+ # result.status = status_double
69
+ # result.stdout = stdout
70
+ #
71
+ # result
72
+ #end
73
+
74
+ def expect_command_success(command_results)
75
+ expect(command_results).to be_success, "Expected command successs but it failed. Got: \n#{command_results.stdout}"
76
+ end
77
+
78
+ def report_raise(e)
79
+ $stderr.puts e.message
80
+ $stderr.puts e.backtrace.join "\n"
81
+ end
82
+
83
+ def capture(&code)
84
+ out = StringIO.new
85
+
86
+ og_stdout = $stdout
87
+ og_stderr = $stderr
88
+ begin
89
+ $stdout = out
90
+ $stderr = out
91
+
92
+ yield
93
+ ensure
94
+ $stdout = og_stdout
95
+ $stderr = og_stderr
96
+ end
97
+
98
+ out.string
99
+ end
100
+
101
+ # Container for the execution results returned by {ExecutableHelpers::execute}
102
+ class ExecutationResult
103
+ # Execution status (as returned by $?)
104
+ attr_accessor :status
105
+ # STDOUT + STDERR as a string
106
+ attr_accessor :stdout
107
+
108
+ def success?
109
+ self.status.success?
110
+ end
111
+ end
112
+ end