nodepile 0.1.1 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,155 @@
1
+
2
+ module Nodepile
3
+
4
+ # Represents a single rule record as represernted by a KeyedArrayAccessor object.
5
+ # Note that this class does not rely on metadata of the KeyedArrayAccessor and doesn't
6
+ # even verify that the object it represents actually contains any formulas.
7
+ #
8
+ # Generally speaking, any field whose first character is a question mark is considered
9
+ # to have a calculation/formula in it. Formulas (not counting the question mark) are simply
10
+ # ruby expressions. The formulas in the id fields ('_id', '_links_to', and '_links_from')
11
+ # are given special treatment as described below.
12
+ #
13
+ # Dynamic calculations must start with the question mark character '?'. They
14
+ # will use the Ruby language itself with a tightly constrained binding that
15
+ # defines one primary object simply named "v" (standing for values). That object
16
+ # only supports a handful of operations including:
17
+ # v['fielaname'] to evaluate a field
18
+ # v.include?('fieldname') to determine whether the field exists
19
+ # v[:this] to evaluate this field without having to explicitly name it
20
+ # of fields. Note that blank "fields" will often return nil and also non-existent
21
+ # fields will be nil.
22
+ #
23
+ # Note, that some exceptional calculation rules may be triggered if this
24
+ # calculation is for an id field. See the #uses_id_calcs?() method.
25
+ class RuleRecordEvaluator
26
+ EDGE_ID_FIELDS = ['_links_from','_links_to'].freeze
27
+ NODE_ID_FIELDS = ['_id'].freeze
28
+ ID_FIELD_NAMES = (NODE_ID_FIELDS + EDGE_ID_FIELDS).freeze
29
+
30
+ # @param rule_record_kaa [KeyedArrayAccessor] This ia a rule record that
31
+ # contains one or more formulas in its fields as indicated
32
+ # by a leading question mark in either _id, _links_from, or _links_to
33
+ def initialize(rule_record_kaa)
34
+ @kaa = rule_record_kaa
35
+ @match_fields = @kaa['_id'].nil? ? EDGE_ID_FIELDS : NODE_ID_FIELDS # assuming it's well formed
36
+ @match_type = nil
37
+ end
38
+
39
+ # Confirm that this particular rule applies to the given node or edge
40
+ # @param otr [KeyedArrayAccessor] confirms that
41
+ # @return [Boolean] true if the identifying fields match. For node entities
42
+ # the '_id' field is the key. For edges, the '_links_from'
43
+ # and '_links_to' fields are the identifying fields.
44
+ def match_record?(otr)
45
+ return @match_fields.all?{|key|
46
+ myval = @kaa[key]
47
+ if myval.start_with?('?')
48
+ self.class.eval_calc(myval,key,otr)
49
+ else
50
+ myval == otr[key]
51
+ end
52
+ }
53
+ end
54
+
55
+ # Returns true if the calculation used by #match_record?() uses complex
56
+ # calculation logic
57
+ def uses_dynamic_match?
58
+ @match_type ||= @match_fields.any?{|k|
59
+ @kaa[k].then{|v| v.start_with?('?') && v.include?('v[')}
60
+ } ? :dynamic : :static
61
+ return @match_type == :dynamic
62
+ end
63
+
64
+ # Calculates the "value" of the rule when applied to a specific record
65
+ # NOTE: this does not test for #match_record?() which you probably want
66
+ # to do first. Note that the three id fields are ALWAYS left as nil after this
67
+ # method. Calculated values will be coerced to string via #to_s so if the
68
+ # default behavior isn't the right one for you, you should convert to string yourself
69
+ # This also doesn't test whether the records conform.
70
+ #
71
+ # @param otr [KeyedArrayAccessor] Rules must be calculated against a given
72
+ # record
73
+ # @return [KeyedArrayAccessor] Calculates an appropriate overlay from the rule
74
+ def calculate_rule(otr)
75
+ kaa = @kaa.dup
76
+ kaa.kv_map!{|k,v|
77
+ if v.nil?
78
+ #no-op
79
+ elsif ID_FIELD_NAMES.include?(k)
80
+ nil # we never overlay key fields
81
+ elsif v.start_with?('?')
82
+ self.class.eval_calc(v,k,otr)&.to_s
83
+ else
84
+ v # leave field unaltered by calculation logic
85
+ end
86
+ }
87
+ return kaa
88
+ end
89
+
90
+ # Evaluate a calculation using standard logic. Formulas may use syntax to
91
+ # reference the values of the eval_against_key_value_map object. For example
92
+ # "?v['column X'].to_f > 17.2 ? 'red' : 'black'" calcs based on 'column X' contents
93
+ def self.eval_calc(rule_field_defn,this_field_name,eval_against_key_value_map)
94
+ return rule_field_defn unless rule_field_defn.start_with?('?')
95
+ begin
96
+ ruby_code = rule_field_defn.dup.tap{|s| s[0] = ' '} # get rid of leading question mark
97
+ val = EvalFrame.evaluate(ruby_code,this_field_name,eval_against_key_value_map)
98
+ rescue StandardError => e
99
+ #TODO: Probably will need to remove this and replace with more fault
100
+ # tolerant strategy that fails gracefully (perhaps by nil-valuing the field)
101
+ raise "Error attempting to evaluate this formula { #{rule_field_defn} } : #{e.message}"
102
+ end
103
+ case val
104
+ when true,false,nil
105
+ #no-op
106
+ when Regexp
107
+ if /^?\s*\//.match?(rule_field_defn) && ID_FIELD_NAMES.include?(this_field_name)
108
+ val = val.match?(eval_against_key_value_map[this_field_name])
109
+ else
110
+ raise "Rule should evaluate to a 'boolean' except when triggering Regex/glob matching on an id field."
111
+ end
112
+ when String
113
+ if /^?\s*['"]/.match?(rule_field_defn) && ID_FIELD_NAMES.include?(this_field_name)
114
+ val = File.fnmatch?(val,eval_against_key_value_map[this_field_name])
115
+ else
116
+ #no-op... returning a string is a good behavior for calculations
117
+ end
118
+ else
119
+ raise "For field [#{this_field_name}] the rule expression must evaluate to true, false, or nil except when triggering regex/glob matching on an id field."
120
+ end #case
121
+ return val
122
+ end
123
+
124
+ private
125
+
126
+ # Utility class
127
+ class HashMask
128
+ def initialize(hashlike,this_key)
129
+ @h = hashlike
130
+ @tk = this_key
131
+ end
132
+
133
+ def include?(k) = @h.include?(k)
134
+ def [](k)
135
+ raise "Unable to use v[:this] because :this was not set" if k == :this && @tk.nil?
136
+ @h[k == :this ? @tk : k]
137
+ end
138
+ end #class HashMask
139
+
140
+ # Utility class
141
+ class EvalFrame
142
+ def initialize(test_hashlike) = @__hm = test_hashlike
143
+ def v = @__hm
144
+
145
+ def self.evaluate(defn,this_fieldname,test_hashlike)
146
+ frame = new(HashMask.new(test_hashlike,this_fieldname)) #restrict access as tightly as reasonable
147
+ frame.instance_eval(defn) # return the result
148
+ end
149
+ end #class EvalFrame
150
+
151
+
152
+
153
+ end #class RuleRecordEvaluator
154
+
155
+ end # module Nodepile
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Nodepile
4
- VERSION = "0.1.1"
4
+ VERSION = "0.1.2"
5
5
  end
data/nodepile.gemspec ADDED
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "lib/nodepile/version"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "nodepile"
7
+ spec.version = Nodepile::VERSION
8
+ spec.authors = ["David Foster"]
9
+ spec.email = ["david.t.foster.01@gmail.com"]
10
+
11
+ spec.summary = "Translate flat text file data into connected graph specs suitable for graphviz. NOT WORKING CODE."
12
+ spec.description = "NOT WORKING CODE. Designed to make it easy to take a spreadsheet or other tabular data and use it to generate, manipulate, and style connected graphs. Can be used from the command line or as an object model. This gem does not itself perform any rendering, although it contains facilities to drive the Graphviz familly of open source tools to generate images (e.g. gif, jpg, svm)."
13
+ spec.required_ruby_version = ">= 3.2.2"
14
+ spec.homepage = "https://rubygems.org/gems/nodepile"
15
+ spec.metadata["homepage_uri"] = spec.homepage
16
+ spec.metadata["source_code_uri"] = "https://gitlab.com/fosterd42/nodepile.git"
17
+ spec.license = "MIT"
18
+ #spec.metadata["allowed_push_host"] = "TODO: Set to your gem server 'https://example.com'"
19
+ #spec.metadata["changelog_uri"] = "TODO: Put your gem's CHANGELOG.md URL here."
20
+
21
+
22
+
23
+ # Specify which files should be added to the gem when it is released.
24
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
25
+ spec.files = Dir.chdir(__dir__) do
26
+ `git ls-files -z`.split("\x0").reject do |f|
27
+ (f == __FILE__) || f.match(%r{\A(?:(?:bin|test|spec|features)/|\.(?:git|circleci)|appveyor)})
28
+ end
29
+ end
30
+ spec.bindir = "exe"
31
+ spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
32
+ spec.require_paths = ["lib"]
33
+
34
+ # Uncomment to register a new dependency of your gem
35
+ # spec.add_dependency "example-gem", "~> 1.0"
36
+ spec.add_dependency 'ruby-graphviz', "~> 1.2.5"
37
+
38
+ # DEVELOPMENT DEPENDENCIES BELOW
39
+ spec.add_development_dependency "rake" , ">= 13.0"
40
+ spec.add_development_dependency "rspec", ">= 3.0"
41
+ spec.add_development_dependency 'rspec-debug', ">= 0.2.0"
42
+ spec.add_development_dependency "rubocop", ">= 1.21"
43
+
44
+ spec.add_development_dependency 'codecov','>= 0.6.0'
45
+ spec.add_development_dependency 'dotenv','>= 2.8.1'
46
+ spec.add_development_dependency 'simplecov', '>= 0.15', '< 0.22'
47
+ spec.add_development_dependency 'yard', '>= 0.9.34'
48
+ spec.add_development_dependency 'webrick', ">= 1.3.1"
49
+
50
+
51
+ # For more information and examples about making a new gem, check out our
52
+ # guide at: https://bundler.io/guides/creating_gem.html
53
+ end
data/tmp/.gitignore ADDED
@@ -0,0 +1 @@
1
+ *
metadata CHANGED
@@ -1,62 +1,166 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: nodepile
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Foster
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-04-05 00:00:00.000000000 Z
11
+ date: 2023-07-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: rake
14
+ name: ruby-graphviz
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 1.2.5
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 1.2.5
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
18
32
  - !ruby/object:Gem::Version
19
33
  version: '13.0'
20
34
  type: :development
21
35
  prerelease: false
22
36
  version_requirements: !ruby/object:Gem::Requirement
23
37
  requirements:
24
- - - "~>"
38
+ - - ">="
25
39
  - !ruby/object:Gem::Version
26
40
  version: '13.0'
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: rspec
29
43
  requirement: !ruby/object:Gem::Requirement
30
44
  requirements:
31
- - - "~>"
45
+ - - ">="
32
46
  - !ruby/object:Gem::Version
33
47
  version: '3.0'
34
48
  type: :development
35
49
  prerelease: false
36
50
  version_requirements: !ruby/object:Gem::Requirement
37
51
  requirements:
38
- - - "~>"
52
+ - - ">="
39
53
  - !ruby/object:Gem::Version
40
54
  version: '3.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec-debug
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: 0.2.0
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: 0.2.0
41
69
  - !ruby/object:Gem::Dependency
42
70
  name: rubocop
43
71
  requirement: !ruby/object:Gem::Requirement
44
72
  requirements:
45
- - - "~>"
73
+ - - ">="
46
74
  - !ruby/object:Gem::Version
47
75
  version: '1.21'
48
76
  type: :development
49
77
  prerelease: false
50
78
  version_requirements: !ruby/object:Gem::Requirement
51
79
  requirements:
52
- - - "~>"
80
+ - - ">="
53
81
  - !ruby/object:Gem::Version
54
82
  version: '1.21'
55
- description: Designed to make it easy to take a spreadsheet or other tabular data
56
- and use it to generate, manipulate, and style connected graphs. Can be used from
57
- the command line or as an object model. This gem does not itself perform any rendering,
58
- although it contains facilities to drive the Graphviz familly of open source tools
59
- to generate images (e.g. gif, jpg, svm).
83
+ - !ruby/object:Gem::Dependency
84
+ name: codecov
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: 0.6.0
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: 0.6.0
97
+ - !ruby/object:Gem::Dependency
98
+ name: dotenv
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: 2.8.1
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: 2.8.1
111
+ - !ruby/object:Gem::Dependency
112
+ name: simplecov
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0.15'
118
+ - - "<"
119
+ - !ruby/object:Gem::Version
120
+ version: '0.22'
121
+ type: :development
122
+ prerelease: false
123
+ version_requirements: !ruby/object:Gem::Requirement
124
+ requirements:
125
+ - - ">="
126
+ - !ruby/object:Gem::Version
127
+ version: '0.15'
128
+ - - "<"
129
+ - !ruby/object:Gem::Version
130
+ version: '0.22'
131
+ - !ruby/object:Gem::Dependency
132
+ name: yard
133
+ requirement: !ruby/object:Gem::Requirement
134
+ requirements:
135
+ - - ">="
136
+ - !ruby/object:Gem::Version
137
+ version: 0.9.34
138
+ type: :development
139
+ prerelease: false
140
+ version_requirements: !ruby/object:Gem::Requirement
141
+ requirements:
142
+ - - ">="
143
+ - !ruby/object:Gem::Version
144
+ version: 0.9.34
145
+ - !ruby/object:Gem::Dependency
146
+ name: webrick
147
+ requirement: !ruby/object:Gem::Requirement
148
+ requirements:
149
+ - - ">="
150
+ - !ruby/object:Gem::Version
151
+ version: 1.3.1
152
+ type: :development
153
+ prerelease: false
154
+ version_requirements: !ruby/object:Gem::Requirement
155
+ requirements:
156
+ - - ">="
157
+ - !ruby/object:Gem::Version
158
+ version: 1.3.1
159
+ description: NOT WORKING CODE. Designed to make it easy to take a spreadsheet or other
160
+ tabular data and use it to generate, manipulate, and style connected graphs. Can
161
+ be used from the command line or as an object model. This gem does not itself perform
162
+ any rendering, although it contains facilities to drive the Graphviz familly of
163
+ open source tools to generate images (e.g. gif, jpg, svm).
60
164
  email:
61
165
  - david.t.foster.01@gmail.com
62
166
  executables: []
@@ -65,20 +169,32 @@ extra_rdoc_files: []
65
169
  files:
66
170
  - ".rspec"
67
171
  - ".rubocop.yml"
172
+ - BACKLOG.md
68
173
  - CHANGELOG.md
69
174
  - Gemfile
70
175
  - README.md
71
176
  - Rakefile
72
177
  - lib/nodepile.rb
178
+ - lib/nodepile/base_structs.rb
179
+ - lib/nodepile/colspecs.rb
180
+ - lib/nodepile/gross_actions.rb
181
+ - lib/nodepile/gviz.rb
182
+ - lib/nodepile/keyed_array.rb
183
+ - lib/nodepile/pile_organizer.rb
184
+ - lib/nodepile/pragmas.rb
185
+ - lib/nodepile/rec_source.rb
186
+ - lib/nodepile/rule_eval.rb
73
187
  - lib/nodepile/version.rb
188
+ - nodepile.gemspec
74
189
  - sig/nodepile.rbs
190
+ - tmp/.gitignore
75
191
  homepage: https://rubygems.org/gems/nodepile
76
192
  licenses:
77
193
  - MIT
78
194
  metadata:
79
195
  homepage_uri: https://rubygems.org/gems/nodepile
80
196
  source_code_uri: https://gitlab.com/fosterd42/nodepile.git
81
- post_install_message:
197
+ post_install_message:
82
198
  rdoc_options: []
83
199
  require_paths:
84
200
  - lib
@@ -86,15 +202,16 @@ required_ruby_version: !ruby/object:Gem::Requirement
86
202
  requirements:
87
203
  - - ">="
88
204
  - !ruby/object:Gem::Version
89
- version: 2.7.0
205
+ version: 3.2.2
90
206
  required_rubygems_version: !ruby/object:Gem::Requirement
91
207
  requirements:
92
208
  - - ">="
93
209
  - !ruby/object:Gem::Version
94
210
  version: '0'
95
211
  requirements: []
96
- rubygems_version: 3.4.6
97
- signing_key:
212
+ rubygems_version: 3.4.10
213
+ signing_key:
98
214
  specification_version: 4
99
- summary: Translate flat text file data into connected graph specs suitable for graphviz.
215
+ summary: Translate flat text file data into connected graph specs suitable for graphviz. NOT
216
+ WORKING CODE.
100
217
  test_files: []