Module: ModelSchema::Dumper

Defined in:
lib/model_schema/dumper.rb

Class Method Summary collapse

Class Method Details

.dump_model_schema(db, path, opts) ⇒ Object

Dumps a valid model_schema into the given file path. Accepts options as per the OptionParser above.



69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
# File 'lib/model_schema/dumper.rb', line 69

def self.dump_model_schema(db, path, opts)
  model = parse_model_file(path)
  abort "In #{path}, couldn't find class that extends Sequel::Model" if !model

  klass = Class.new(Sequel::Model(model[:table_name]))
  klass.db = db
  klass.plugin(ModelSchema::Plugin)

  # dump table generator given by model_schema
  generator = klass.send(:table_generator)
  commands = [generator.dump_columns, generator.dump_constraints,
              generator.dump_indexes].reject{|s| s == ''}.join("\n\n")

  # account for indentation
  tab = opts[:tabbing] == 0 ? "\t" : ' ' * opts[:tabbing]
  schema_indentation = model[:indentation] + tab
  command_indentation = schema_indentation + tab

  commands = commands.lines.map {|l| l == "\n" ? l : command_indentation + l}.join
  commands = commands.gsub('=>', ' => ')

  dump_lines = ["#{schema_indentation}model_schema do\n",
                "#{commands}\n",
                "#{schema_indentation}end\n"]

  lines = model[:lines_before] + dump_lines + model[:lines_after]
  File.write(path, lines.join)
end

.parse_model_file(path) ⇒ Object

Parses the model file at the given path, returning a hash of the form:

:table_name => the model table name :lines_before => an array of lines before the expected model schema dump :lines_after => an array of lines after the expected model schema dump :indentation => the indentation (leading whitespace) of the model class

Returns nil if the file couldn’t be parsed.



106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
# File 'lib/model_schema/dumper.rb', line 106

def self.parse_model_file(path)
  lines = File.read(path).lines

  lines.each_with_index do |line, index|
    match = SEQUEL_MODEL_REGEX.match(line)

    if match
      # extract table name as symbol
      table_name = match[1]
      if table_name[0] == ':'
        table_name = table_name[1..-1].to_sym
      else
        abort "In #{path}, can't find a symbol table name in line: #{line}"
      end

      # indentation for model_schema block
      indentation = LEADING_WHITESPACE_REGEX.match(line)[0]

      return {
        :table_name => table_name.to_sym,
        :lines_before => lines[0..index],
        :lines_after => lines[(index + 1)..-1],
        :indentation => indentation,
      }
    end
  end

  nil
end

.run(args) ⇒ Object

Parses options and then dumps the model schema.



9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
# File 'lib/model_schema/dumper.rb', line 9

def self.run(args)
  opts = {}
  opts[:tabbing] = 2

  parser = OptionParser.new do |p|
    p.banner = 'Usage: dump_model_schema [options] model_file [model_file ...]'
    p.separator "\nDumps a valid model_schema block in each given model_file.\n\n"

    p.on('-c', '--connection CONNECTION',
         'Connection string for database') do |connection|
      opts[:connection] = connection
    end

    p.on('-t', '--tabbing TABBING', Integer,
              'Number of spaces for tabbing, or 0 for hard tabs') do |tabbing|
      opts[:tabbing] = tabbing
    end

    p.on('-v', '--version', 'Print version') do
      puts ModelSchema::VERSION
      exit
    end

    p.on('-h', '--help', 'Print help') do
      puts parser
      exit
    end
  end

  model_files = parser.parse(args)

  # model and connection are required
  abort 'Must provide at least one model file.' if model_files.empty?
  abort 'Must provide a connection string with -c or --connection.' if !opts[:connection]

  db = Sequel.connect(opts[:connection])
  db.extension(:schema_dumper)

  if db.is_a?(Sequel::Postgres::Database)
    # include all Postgres type extensions so schema dumps are accurate
    db.extension(:pg_array, :pg_enum, :pg_hstore, :pg_inet, :pg_json,
                 :pg_range, :pg_row)
  end

  had_error = false
  model_files.each do |path|
    begin
      dump_model_schema(db, path, opts)
    rescue StandardError, SystemExit => error
      # SystemExit error messages are already printed by abort()
      $stderr.puts error.message if error.is_a?(StandardError)
      had_error = true
    end
  end

  exit 1 if had_error
end