Class: Sequel::Annotate

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

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(model) ⇒ Annotate

Store the model to annotate



44
45
46
# File 'lib/sequel/annotate.rb', line 44

def initialize(model)
  @model = model
end

Instance Attribute Details

#modelObject (readonly)

The model to annotate



41
42
43
# File 'lib/sequel/annotate.rb', line 41

def model
  @model
end

Class Method Details

.annotate(paths, options = {}) ⇒ Object

Append/replace the schema comment for all of the given files. Attempts to guess the model for each file using a regexp match of the file’s content, if this doesn’t work, you’ll need to create an instance manually and pass in the model and path. Example:

Sequel::Annotate.annotate(Dir['models/*.rb'])


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
# File 'lib/sequel/annotate.rb', line 11

def self.annotate(paths, options = {})
  Sequel.extension :inflector
  namespace = options[:namespace]

  paths.each do |path|
    text = File.read(path)

    next if text.match(/^#\s+sequel-annotate:\s+false$/i)

    name = nil
    if namespace == true
      constants = text.scan(/\bmodule ([^\s]+)|class ([^\s<]+)\s*</).flatten.compact
      name = constants.join("::") if constants.any?
    elsif match = text.match(/class ([^\s<]+)\s*</)
      name = match[1]
      if namespace
        name = "#{namespace}::#{name}"
      end
    end

    if name
      klass = name.constantize
      if klass.ancestors.include?(Sequel::Model)
        new(klass).annotate(path, options)
      end
    end
  end
end

Instance Method Details

#annotate(path, options = {}) ⇒ Object

Append the schema comment (or replace it if one already exists) to the file at the given path.



50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
# File 'lib/sequel/annotate.rb', line 50

def annotate(path, options = {})
  return if skip_model?

  orig = current = File.read(path).rstrip

  if options[:position] == :before
    if current =~ /\A((?:^\s*$|^#\s*(?:frozen_string_literal|coding|encoding|warn_indent|warn_past_scope)[^\n]*\s*)*)/m
      magic_comments = $1
      current.slice!(0, magic_comments.length)
    end

    current = current.gsub(/\A#\sTable[^\n\r]+\r?\n(?:#[^\n\r]*\r?\n)*/m, '').lstrip
    current = "#{magic_comments}#{schema_comment(options)}#{$/}#{$/}#{current}"
  else
    if m = current.reverse.match(/#{"#{$/}# Table: ".reverse}/m)
      offset = current.length - m.end(0) + 1
      unless current[offset..-1].match(/^[^#]/)
        # If Table: comment exists, and there are no
        # uncommented lines between it and the end of the file
        # then replace current comment instead of appending it
        current = current[0...offset].rstrip
      end
    end
    current += "#{$/}#{$/}#{schema_comment(options)}"
  end

  if orig != current
    File.open(path, "wb") do |f|
      f.puts current
    end
  end
end

#schema_comment(options = {}) ⇒ Object

The schema comment to use for this model.

For all databases, includes columns, indexes, and foreign key constraints in this table referencing other tables. On PostgreSQL, also includes check constraints, triggers, and foreign key constraints in other tables referencing this table.

Options:

:border

Include a border above and below the comment.

:indexes

Do not include indexes in annotation if set to false.

:foreign_keys

Do not include foreign key constraints in annotation if set to false.

PostgreSQL-specific options:

:constraints

Do not include check constraints if set to false.

:references

Do not include foreign key constraints in other tables referencing this table if set to false.

:triggers

Do not include triggers in annotation if set to false.



99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
# File 'lib/sequel/annotate.rb', line 99

def schema_comment(options = {})
  return "" if skip_model?

  output = []
  output << "# Table: #{model.dataset.with_quote_identifiers(false).literal(model.table_name)}"

  meth = :"_schema_comment_#{model.db.database_type}"
  if respond_to?(meth, true)
    send(meth, output, options)
  else
    schema_comment_columns(output)
    schema_comment_indexes(output) unless options[:indexes] == false
    schema_comment_foreign_keys(output) unless options[:foreign_keys] == false
  end


  # Add beginning and end to the table if specified
  if options[:border]
    border = "# #{'-' * (output.map(&:size).max - 2)}"
    output.push(border)
    output.insert(1, border)
  end

  output.join($/)
end