asi_bod 0.1.2

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.
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source 'https://rubygems.org'
2
+ gemspec
data/README.rdoc ADDED
@@ -0,0 +1,33 @@
1
+ = NAME asi_bod
2
+
3
+ - Manipulate and view the ASIObjectDictionary.xml and BOD.json files
4
+
5
+ == SYNOPSIS
6
+ asi_bod [global options] command [command options] [arguments...]
7
+
8
+ == Overview
9
+
10
+ Tool to view, search and potentially merge the Grin Tech Phaserunner +BOD.json+
11
+ file and the ASI +ASIObjectDictionary.xml+ file.
12
+
13
+ The +BOD.json+ file is the original Grin Tech file that ships with the
14
+ +PhaseRunner v0.9.9.1+ software as of Jan 1 2018.
15
+
16
+ This gem ships with +BODm.json+ which is the same as the Grin Tech +BOD.json+ except
17
+ the Descriptions from the ASI +ASIObjectDictionary.xml+ file that shipped with the
18
+ +BacDoorSetup_1_5_4+ software.
19
+
20
+ If you want to start with the original or another version of the +BOD.json+ or the
21
+ +ASIObjectDictionary.xml+ then you can override the defaults with the +-a,
22
+ --asi_file+ or +-b, --bod_file+ flags
23
+
24
+ == COMMANDS
25
+ find - Find a node in one or both of the dictionaries
26
+ help - Shows a list of commands or help for one command
27
+ merge - Merge the Description from asi to bod
28
+ view - View the data
29
+
30
+ == Detailed Command Line Info
31
+
32
+ :include: asi_bod.rdoc
33
+
data/Rakefile ADDED
@@ -0,0 +1,48 @@
1
+ require 'rake/clean'
2
+ require 'rubygems'
3
+ require 'rubygems/package_task'
4
+ require 'rdoc/task'
5
+ require 'cucumber'
6
+ require 'cucumber/rake/task'
7
+ Rake::RDocTask.new do |rd|
8
+ rd.main = "README.rdoc"
9
+ rd.rdoc_files.include("README.rdoc","lib/**/*.rb","bin/**/*")
10
+ rd.title = 'Your application title'
11
+ end
12
+
13
+ # task :rdoc_to_md
14
+ # ruby -r rdoc -e 'puts RDoc::Markup::ToMarkdown.new.convert File.read(ARGV[0] || "README.rdoc")' | grep -v ':include:' >README.md
15
+ # ruby -r rdoc -e 'puts RDoc::Markup::ToMarkdown.new.convert File.read(ARGV[0] || "asi_bod.rdoc")' >> README.md
16
+
17
+ spec = eval(File.read('asi_bod.gemspec'))
18
+
19
+ Gem::PackageTask.new(spec) do |pkg|
20
+ end
21
+ CUKE_RESULTS = 'results.html'
22
+ CLEAN << CUKE_RESULTS
23
+ desc 'Run features'
24
+ Cucumber::Rake::Task.new(:features) do |t|
25
+ opts = "features --format html -o #{CUKE_RESULTS} --format progress -x"
26
+ opts += " --tags #{ENV['TAGS']}" if ENV['TAGS']
27
+ t.cucumber_opts = opts
28
+ t.fork = false
29
+ end
30
+
31
+ desc 'Run features tagged as work-in-progress (@wip)'
32
+ Cucumber::Rake::Task.new('features:wip') do |t|
33
+ tag_opts = ' --tags ~@pending'
34
+ tag_opts = ' --tags @wip'
35
+ t.cucumber_opts = "features --format html -o #{CUKE_RESULTS} --format pretty -x -s#{tag_opts}"
36
+ t.fork = false
37
+ end
38
+
39
+ task :cucumber => :features
40
+ task 'cucumber:wip' => 'features:wip'
41
+ task :wip => 'features:wip'
42
+ require 'rake/testtask'
43
+ Rake::TestTask.new do |t|
44
+ t.libs << "test"
45
+ t.test_files = FileList['test/*_test.rb']
46
+ end
47
+
48
+ task :default => [:test,:features]
data/asi_bod.gemspec ADDED
@@ -0,0 +1,46 @@
1
+
2
+ lib = File.expand_path("../lib", __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require "asi_bod/version"
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "asi_bod"
8
+ spec.version = AsiBod::VERSION
9
+ spec.authors = ["Robert J. Berger"]
10
+ spec.email = ["rberger@ibd.com"]
11
+
12
+ spec.summary = %q{Process and View Grin Phaserunner ASIObjectDictionary.xml and BOD.json files}
13
+ spec.description = %q{Process and View Grin Phaserunner ASIObjectDictionary.xml and BOD.json files}
14
+ spec.homepage = "https://github.com/rberger/asi_bod"
15
+ spec.license = "MIT"
16
+
17
+ # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
18
+ # to allow pushing to a single host or delete this section to allow pushing to any host.
19
+ # if spec.respond_to?(:metadata)
20
+ # spec.metadata["allowed_push_host"] = "TODO: Set to 'http://mygemserver.com'"
21
+ # else
22
+ # raise "RubyGems 2.0 or newer is required to protect against " \
23
+ # "public gem pushes."
24
+ # end
25
+
26
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
27
+ f.match(%r{^(test|spec|features)/})
28
+ end
29
+ spec.bindir = "exe"
30
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
31
+ spec.require_paths = ["lib"]
32
+
33
+ spec.has_rdoc = true
34
+ spec.extra_rdoc_files = ['README.rdoc','asi_bod.rdoc']
35
+ spec.rdoc_options << '--title' << 'asi_bod' << '--main' << 'README.rdoc' << '-ri'
36
+
37
+ spec.add_development_dependency "bundler", "~> 1.16"
38
+ spec.add_development_dependency "rake", "~> 10.0"
39
+ spec.add_development_dependency "rspec", "~> 3.0"
40
+ spec.add_development_dependency "rdoc", "~> 6.0"
41
+ spec.add_development_dependency "aruba", "~> 0.14"
42
+ spec.add_runtime_dependency "gli","~> 2.17"
43
+ spec.add_runtime_dependency "nori","~> 2.6"
44
+ spec.add_runtime_dependency "nokogiri", "~> 1.8"
45
+
46
+ end
data/asi_bod.rdoc ADDED
@@ -0,0 +1,119 @@
1
+ == asi_bod - Manipulate and view the ASIObjectDictionary.xml and BOD.json files
2
+
3
+ v0.1.2
4
+
5
+ === Global Options
6
+ === -a|--asi_file arg
7
+
8
+ Path to the ASIObjectDictionary XML file
9
+
10
+ [Default Value] /Users/rberger/odrive/IBD Google Drive/Trike/bike-pi/asi_bod/ASIObjectDictionary.xml
11
+
12
+
13
+ === -b|--bod_file arg
14
+
15
+ Path to the BOD JSON file
16
+
17
+ [Default Value] /Users/rberger/odrive/IBD Google Drive/Trike/bike-pi/asi_bod/BODm.json
18
+
19
+
20
+ === --[no-]address_view
21
+ View Address
22
+
23
+
24
+
25
+ === --[no-]description_view
26
+ View Description
27
+
28
+
29
+
30
+ === --help
31
+ Show this message
32
+
33
+
34
+
35
+ === --[no-]name_view
36
+ View Name
37
+
38
+
39
+
40
+ === -s|--[no-]scale_view
41
+ View Scale
42
+
43
+
44
+
45
+ === -u|--[no-]units_view
46
+ View Units
47
+
48
+
49
+
50
+ === --version
51
+ Display the program version
52
+
53
+
54
+
55
+ === Commands
56
+ ==== Command: <tt>find </tt>
57
+ Find a node in one or both of the dictionaries
58
+
59
+
60
+ ===== Options
61
+ ===== -a|--[no-]asi
62
+ Search the asi dictionary
63
+
64
+
65
+
66
+ ===== -b|--[no-]bod
67
+ Search the bod dictionary
68
+
69
+
70
+
71
+ ===== Commands
72
+ ====== Command: <tt>by_address </tt>
73
+ Find by register address
74
+
75
+ Find by register address. Must select at least one of asi or bod and specify search_term
76
+ ====== Command: <tt>by_key_substring </tt>
77
+ Find by the substring of a key
78
+
79
+ Find by the substring of a Must select at least one of asi or bod and specify search_term
80
+ ==== Command: <tt>help command</tt>
81
+ Shows a list of commands or help for one command
82
+
83
+ Gets help for the application or its commands. Can also list the commands in a way helpful to creating a bash-style completion function
84
+ ===== Options
85
+ ===== -c
86
+ List commands one per line, to assist with shell completion
87
+
88
+
89
+
90
+ ==== Command: <tt>merge </tt>
91
+ Merge the Description from asi to bod
92
+
93
+ Merge the Description from asi to bod Do not merge if Description has "Reserved" in it Or if the Bod doesnt have the key
94
+ ===== Options
95
+ ===== -j|--[no-]json
96
+ Output Json
97
+
98
+
99
+
100
+ ==== Command: <tt>view </tt>
101
+ View the data
102
+
103
+
104
+ ===== Options
105
+ ===== -j|--[no-]json
106
+ Output as Json instead of CSV
107
+
108
+
109
+
110
+ ===== Commands
111
+ ====== Command: <tt>asi </tt>
112
+ Pretty Print output of the simplified ASI ObjectDictionary as a hash
113
+
114
+
115
+ ====== Command: <tt>bod </tt>
116
+ Pretty Print output of the simplified BOD as a hash
117
+
118
+
119
+ [Default Command] bod
data/exe/asi_bod ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'asi_bod'
4
+
5
+ cli = AsiBod::Cli.new
6
+ cli.main
data/lib/asi_bod.rb ADDED
@@ -0,0 +1,6 @@
1
+ require 'asi_bod/gli_patch.rb'
2
+ require 'asi_bod/version.rb'
3
+ require 'asi_bod/cli.rb'
4
+ require 'asi_bod/asi.rb'
5
+ require 'asi_bod/bod.rb'
6
+ require 'asi_bod/dict.rb'
@@ -0,0 +1,33 @@
1
+
2
+ require 'nori'
3
+
4
+ module AsiBod
5
+ class Asi
6
+ attr_reader :nori
7
+ attr_reader :raw_data
8
+ attr_reader :array_data
9
+ attr_reader :hash_data
10
+
11
+ def initialize(global_options, options, args)
12
+ @nori = Nori.new
13
+ @raw_data = @nori.parse(File.read(global_options[:asi_file]))
14
+ @array_data = @raw_data["InternalAppEntity"]["Parameters"].first[1]
15
+ @hash_data = array_data_to_hash(@array_data)
16
+ end
17
+
18
+ # Convert the array of hashes to a hash with the address as primary key
19
+ def array_data_to_hash(array_data)
20
+ array_data.each_with_object({}) do |node, memo|
21
+ memo[node["Address"].to_i] = clean_node(node)
22
+ end
23
+ end
24
+
25
+ def clean_node(node)
26
+ node.each_with_object({}) do |(k,v), memo|
27
+ next if k == "@FaultIndicator" || k == "BitField" # Skip these pairs
28
+ key = k.sub(k[0], k[0].downcase) # Make it uncapitalized
29
+ memo[key.to_sym] = v
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,24 @@
1
+ require 'json'
2
+
3
+ module AsiBod
4
+ class Bod
5
+ attr_reader :hash_data
6
+
7
+ def initialize(global,options,args)
8
+ @json_data = JSON.parse(File.read(global[:bod_file]))
9
+ @hash_data = json_data_to_hash(@json_data)
10
+ end
11
+
12
+ def json_data_to_hash(json_data)
13
+ json_data.each_with_object({}) do |(k, v), memo|
14
+ memo[k.to_i] = clean_node(v)
15
+ end
16
+ end
17
+
18
+ def clean_node(node)
19
+ node.each_with_object({}) do |(k, v), memo|
20
+ memo[k.to_sym] = v
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,191 @@
1
+ require 'gli'
2
+ require 'json'
3
+ require 'pp'
4
+
5
+ module AsiBod
6
+
7
+ class Cli
8
+ attr_reader :asi
9
+ attr_reader :bod
10
+
11
+ include GLI::App
12
+
13
+ GPARENT = GLI::Command::PARENT
14
+
15
+ KEY_ORDER = {address: 0,
16
+ name: 1,
17
+ description: 2,
18
+ scale: 3,
19
+ units: 4,
20
+ read: 5,
21
+ write: 6}
22
+
23
+ def which_keys(options)
24
+ options.each_with_object([]) do |(k,v), memo|
25
+ if k.is_a?(String) && k.include?("_view")
26
+ # Its a view key
27
+ next unless options[k]
28
+ # Strip off the '_view' and convert to a symbol
29
+ key = k[0..(k.index("_view") - 1)].to_sym
30
+ # Store them in KEY_ORDER
31
+ memo[KEY_ORDER[key]] = key
32
+ end
33
+ end.compact
34
+ end
35
+
36
+ def main
37
+ program_desc 'Manipulate and view the ASIObjectDictionary.xml and BOD.json files'
38
+
39
+ version AsiBod::VERSION
40
+
41
+ subcommand_option_handling :normal
42
+ arguments :strict
43
+
44
+ desc 'Path to the ASIObjectDictionary XML file'
45
+ default_value File.expand_path('../../../ASIObjectDictionary.xml', __FILE__)
46
+ flag [:a,:asi_file]
47
+
48
+ desc 'Path to the BOD JSON file'
49
+ default_value File.expand_path('../../../BODm.json', __FILE__)
50
+ flag [:b,:bod_file]
51
+
52
+ desc 'View Address'
53
+ switch :address_view, default_value: true
54
+
55
+ desc 'View Name'
56
+ switch :name_view, default_value: true
57
+
58
+ desc 'View Description'
59
+ switch :description_view, default_value: true
60
+
61
+ desc 'View Scale'
62
+ switch [:s, :scale_view]
63
+
64
+ desc 'View Units'
65
+ switch [:u, :units_view]
66
+
67
+ desc 'View the data'
68
+ command :view do |view|
69
+ view.desc "Pretty Print output of the simplified ASI ObjectDictionary as a hash"
70
+ view.command :asi do |view_asi|
71
+ view.desc "Output as Json instead of CSV"
72
+ view.switch [:j, :json]
73
+
74
+ view_asi.action do |global_options,options,args|
75
+ if options[GPARENT][:json]
76
+ puts JSON.pretty_generate asi.hash_data
77
+ else
78
+ Dict.put_results(asi.hash_data, which_keys(global_options))
79
+ end
80
+ end
81
+ end
82
+
83
+ view.desc "Pretty Print output of the simplified BOD as a hash"
84
+ view.command :bod do |view_bod|
85
+ view_bod.action do |global_options,options,args|
86
+ if options[GPARENT][:json]
87
+ puts JSON.pretty_generate bod.hash_data
88
+ else
89
+ Dict.put_results(bod.hash_data, which_keys(global_options))
90
+ end
91
+ end
92
+ end
93
+ view.default_command :bod
94
+ end
95
+
96
+ desc 'Find a node in one or both of the dictionaries'
97
+ command :find do |find|
98
+ find.desc "Search the asi dictionary"
99
+ find.switch [:a, :asi]
100
+
101
+ find.desc "Search the bod dictionary"
102
+ find.switch [:b, :bod]
103
+
104
+ find.desc "Find by register address"
105
+ find.long_desc %{Find by register address. } +
106
+ %{Must select at least one of } +
107
+ %{asi or bod and specify search_term}
108
+ find.arg 'address'
109
+ find.command :by_address do |find_by_address|
110
+ find_by_address.action do |global_options,options,args|
111
+ address = args.first
112
+ # puts "find_by_address global_options #{global_options.inspect} options: #{options.inspect} args: #{args.inspect}"
113
+ puts "asi: => " +
114
+ "#{Dict.node_line(asi.hash_data[address.to_i],
115
+ which_keys(global_options))}" if options[GPARENT][:asi]
116
+ puts "bod: => " +
117
+ "#{Dict.node_line(bod.hash_data[address.to_i],
118
+ which_keys(global_options))}" if options[GPARENT][:bod]
119
+ end
120
+ end
121
+
122
+ find.desc "Find by the substring of a key"
123
+ find.long_desc %{Find by the substring of } +
124
+ %{a Must select at least one of } +
125
+ %{asi or bod and specify search_term}
126
+ find.arg 'node_key'
127
+ find.arg 'substring'
128
+ find.command :by_key_substring do |find_by_key_substring|
129
+ find_by_key_substring.action do |global_options,options,args|
130
+ key = args[0].to_sym
131
+ substring = args[1]
132
+ if options[GPARENT][:asi]
133
+ puts "asi: key: #{key} substring: #{substring} => "
134
+ Dict.put_results(
135
+ Dict.find_by_key_substring(asi.hash_data, key, substring),
136
+ which_keys(global_options))
137
+ end
138
+ if options[GPARENT][:bod]
139
+ puts "bod: key: #{key} substring: #{substring} => "
140
+ Dict.put_results(
141
+ Dict.find_by_key_substring(bod.hash_data, key, substring),
142
+ which_keys(global_options))
143
+ end
144
+ end
145
+ end
146
+ end
147
+
148
+ desc 'Merge the Description from asi to bod'
149
+ long_desc 'Merge the Description from asi to bod ' +
150
+ 'Do not merge if Description has "Reserved" in it ' +
151
+ 'Or if the Bod doesnt have the key'
152
+ command :merge do |merge|
153
+ merge.desc 'Output Json'
154
+ merge.switch [:j, :json]
155
+ merge.action do |global_options,options,args|
156
+ raw_result = Dict.merge(asi.hash_data, bod.hash_data)
157
+ if options[:json]
158
+ result = JSON.pretty_generate raw_result
159
+ else
160
+ result = raw_result.pretty_inspect
161
+ end
162
+ puts result
163
+ end
164
+ end
165
+
166
+ pre do |global_options,command,options,args|
167
+ # Pre logic here
168
+ # Return true to proceed; false to abort and not call the
169
+ # chosen command
170
+ # Use skips_pre before a command to skip this block
171
+ # on that command only
172
+ @asi = AsiBod::Asi.new(global_options,options,args)
173
+ @bod = AsiBod::Bod.new(global_options,options,args)
174
+ end
175
+
176
+ post do |global_options,command,options,args|
177
+ # Post logic here
178
+ # Use skips_post before a command to skip this
179
+ # block on that command only
180
+ end
181
+
182
+ on_error do |exception|
183
+ # Error logic here
184
+ # return false to skip default error handling
185
+ true
186
+ end
187
+
188
+ exit run(ARGV)
189
+ end
190
+ end
191
+ end