Class: FixtureFox::Fox

Inherits:
Object
  • Object
show all
Defined in:
lib/fixture_fox.rb

Overview

Fox is compiled incrementally so you can add some files, parse them into an AST, inspect the result through #idr, and then add some more files. The #idr can also be regenerated by executing #call with a different set of seed table IDs

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(type, files = [], schema: nil, ids: nil, anchors: nil) ⇒ Fox

Returns a new instance of Fox.



83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
# File 'lib/fixture_fox.rb', line 83

def initialize(type, files = [], schema: nil, ids: nil, anchors: nil)
  constrain type, PgGraph::Type
  constrain files, [String]
  constrain ids, { String => Integer }, nil
  constrain anchors, Anchors, [Hash], NilClass
  @type = type
  @files = []
  @schema = schema || "public"
  @ids = ids || {}

  if anchors.is_a?(Array)
    @anchors = Anchors.new(type, anchors)
  else
    @anchors = anchors || Anchors.new(type)
  end

  @lines = []
  @ast = nil
  @analyzer = nil
  @idr = nil
  @data = nil
  @frozen = false
  if !files.empty?
    compile(files)
    assign_types # Analyze as far as possible without requiring anchors & ids
    freeze!
  end
end

Instance Attribute Details

#analyzerObject (readonly)

The Analyzer object. The analyzer object is recalculated after new files are added



40
41
42
# File 'lib/fixture_fox.rb', line 40

def analyzer
  @analyzer
end

#anchorsObject (readonly)

Anchors object. #anchors is modified as more and more files are added



59
60
61
# File 'lib/fixture_fox.rb', line 59

def anchors
  @anchors
end

#astObject (readonly)

The AST object. The AST object is a snapshot and grows as more files are parsed



36
37
38
# File 'lib/fixture_fox.rb', line 36

def ast
  @ast
end

#fileObject (readonly)

Name of first source file



25
26
27
# File 'lib/fixture_fox.rb', line 25

def file
  @file
end

#filesObject (readonly)

Names of all source files except included files. FIXME: Not maintained - always []



28
29
30
# File 'lib/fixture_fox.rb', line 28

def files
  @files
end

#idsObject (readonly)

Map from qualified table name to max ID for that table. This is the same as the number of records in the table if the IDs wasn’t seeded with a start value in #initialize



56
57
58
# File 'lib/fixture_fox.rb', line 56

def ids
  @ids
end

#linesObject (readonly)

Tokenized lines. Note that this doesn’t include lines from included files



32
33
34
# File 'lib/fixture_fox.rb', line 32

def lines
  @lines
end

#schemaObject (readonly)

Default schema. Defaults to “public”



51
52
53
# File 'lib/fixture_fox.rb', line 51

def schema
  @schema
end

#typeObject (readonly)

The type of the database (PgGraph::Type::Database object)



22
23
24
# File 'lib/fixture_fox.rb', line 22

def type
  @type
end

Class Method Details

.read_anchors(type, file) ⇒ Object



204
# File 'lib/fixture_fox.rb', line 204

def self.read_anchors(type, file) Anchors.load(type, file) end

.read_ids(file) ⇒ Object



201
# File 'lib/fixture_fox.rb', line 201

def self.read_ids(file) YAML.load(IO.read(file)) end

.read_state(type, file) ⇒ Object



207
208
209
210
211
212
213
214
# File 'lib/fixture_fox.rb', line 207

def self.read_state(type, file)
  if File.size?(file)
    state = YAML.load(IO.read(file))
    [state[:ids], Anchors.new(type, state[:anchors])]
  else
    [nil, nil]
  end
end

.write_anchors(anchors, file) ⇒ Object



205
# File 'lib/fixture_fox.rb', line 205

def self.write_anchors(anchors, file) anchors.save(file) end

.write_ids(ids, file) ⇒ Object



202
# File 'lib/fixture_fox.rb', line 202

def self.write_ids(ids, file) IO.write(file, YAML.dump(ids)) end

.write_state(ids, anchors, file) ⇒ Object



216
217
218
# File 'lib/fixture_fox.rb', line 216

def self.write_state(ids, anchors, file)
  IO.write(file, YAML.dump({ ids: ids, anchors: anchors.to_yaml }))
end

Instance Method Details

#analyze(anchors: nil) ⇒ Object



148
149
150
151
152
153
# File 'lib/fixture_fox.rb', line 148

def analyze(anchors: nil)
#     puts "analyze"
  constrain anchors, Anchors, NilClass
  assign_types if !assigned?
  check_types(anchors: anchors) if !checked?
end

#analyzed?Boolean

Returns:

  • (Boolean)


74
# File 'lib/fixture_fox.rb', line 74

def analyzed?() assigned? && checked? end

#assign_typesObject



155
156
157
158
159
160
161
# File 'lib/fixture_fox.rb', line 155

def assign_types
#     puts "assign_types"
  @analyzer = Analyzer.new(@type, @ast, ids: ids, anchors: anchors)
  @ids = @analyzer.ids
  @anchors = @analyzer.anchors
  @analyzer.assign_types
end

#assigned?Boolean

Returns:

  • (Boolean)


72
# File 'lib/fixture_fox.rb', line 72

def assigned?() !@analyzer.nil? && @analyzer.assigned? end

#check_types(anchors: nil) ⇒ Object



163
164
165
166
167
168
# File 'lib/fixture_fox.rb', line 163

def check_types(anchors: nil)
#     puts "check_types"
  constrain anchors, Anchors, NilClass
  assign_types if !assigned?
  @analyzer.check_types(anchors: anchors)
end

#checked?Boolean

Returns:

  • (Boolean)


73
# File 'lib/fixture_fox.rb', line 73

def checked?() assigned? && @analyzer.checked? end

#compile(*file_or_texts) ⇒ Object



119
120
121
122
123
124
125
126
127
128
129
# File 'lib/fixture_fox.rb', line 119

def compile(*file_or_texts)
  !frozen? or raise Error, "Frozen Fox object"
  @analyzer = nil
  @idr = nil
  @data = nil
  @ast ||= Ast.new
  Array(file_or_texts).flatten.each { |source|
    source, lines = tokenize(source)
    parse(source, lines)
  }
end

#data(anchors: nil, ids: nil) ⇒ Object

PgGraph::Data::Database object of the Idr object



178
179
180
181
182
# File 'lib/fixture_fox.rb', line 178

def data(anchors: nil, ids: nil)
  constrain anchors, Anchors, NilClass
  generate(anchors: anchors, ids: ids) if !generated?
  @data = PgGraph::Data.new(type, idr.to_h)
end

#defined_anchorsObject

List of anchors defined by the sources



62
63
64
# File 'lib/fixture_fox.rb', line 62

def defined_anchors()
  @analyzer.defined_anchors.values
end

#dupObject

Note: Doesn’t dup the Ast or other internal data structures except ids and anchors



114
115
116
117
# File 'lib/fixture_fox.rb', line 114

def dup
  generate if !generated?
  Fox.new(type)
end

#freeze!Object

Freeze the Fox object. After this no more files can be added



81
# File 'lib/fixture_fox.rb', line 81

def freeze!() @frozen = true end

#frozen?Boolean

Returns true if the Fox object is frozen and no more files can be added

Returns:

  • (Boolean)


78
# File 'lib/fixture_fox.rb', line 78

def frozen?() @frozen end

#generate(anchors: nil, ids: nil) ⇒ Object



170
171
172
173
174
175
# File 'lib/fixture_fox.rb', line 170

def generate(anchors: nil, ids: nil)
#     puts "generate"
  constrain anchors, Anchors, NilClass
  analyze(anchors: anchors) if !analyzed?
  @idr = @analyzer.generate(ids: ids)
end

#generated?Boolean

TODO: Rephrase in terms of Analyzer#generated?

Returns:

  • (Boolean)


75
# File 'lib/fixture_fox.rb', line 75

def generated?() !@idr.nil? end

#idrObject

The IDR object. It is reset every time a new file is added



43
# File 'lib/fixture_fox.rb', line 43

def idr() @idr || generate end

#parse(source, lines) ⇒ Object



141
142
143
144
145
146
# File 'lib/fixture_fox.rb', line 141

def parse(source, lines)
#     puts "parse(#{source.inspect})"
  parser = Parser.new(source, lines, schema: @schema)
  @ast = parser.call(@ast)
  parser.anchor_files.each { |file| @anchors.merge!(Anchors.load(@type, file)) }
end

#parsed?Boolean

Returns:

  • (Boolean)


71
# File 'lib/fixture_fox.rb', line 71

def parsed?() !@ast.nil? end

#referenced_anchorsObject

List of external anchors referenced by the sources. FIXME: Unused



67
68
69
# File 'lib/fixture_fox.rb', line 67

def referenced_anchors()
  @analyzer.referenced_anchors.values
end

#tablesObject

List of tables with records (PgGraph::Type::Table)



46
47
48
# File 'lib/fixture_fox.rb', line 46

def tables()
  @analyzer.data_tables
end

#to_sql(format: :psql, ids: nil, delete: :all) ⇒ Object



192
193
194
195
196
197
198
199
# File 'lib/fixture_fox.rb', line 192

def to_sql(format: :psql, ids: nil, delete: :all)
  if [:touched, :recursive, :all].include?(delete)
    # Ugly quick-fix because pg_graph doens't to dependencies(!)
    data.to_sql(format: format, ids: ids || {}, delete: :none, truncate: delete, files: files)
  else
    data.to_sql(format: format, ids: ids || {}, delete: delete, files: files)
  end
end

#to_yamlObject



188
189
190
# File 'lib/fixture_fox.rb', line 188

def to_yaml
  data.to_yaml.to_yaml
end

#tokenize(source) ⇒ Object



131
132
133
134
135
136
137
138
139
# File 'lib/fixture_fox.rb', line 131

def tokenize(source)
#     puts "tokenize(#{source.inspect})"
  tokenizer = Tokenizer.new(source)
  @file ||= tokenizer.file
  @files.append tokenizer.file
  lines = tokenizer.call
  @lines.append(*lines)
  [source, lines]
end

#write_state(file) ⇒ Object



184
185
186
# File 'lib/fixture_fox.rb', line 184

def write_state(file)
  self.class.write_state(ids, anchors, file)
end