asi_bod 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
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