Class: RailroadDiagrams::Document
- Inherits:
-
Object
- Object
- RailroadDiagrams::Document
- Defined in:
- lib/railroad_diagrams/document.rb
Overview
Renders linked diagrams for named grammar rules in one HTML document.
Instance Attribute Summary collapse
-
#locale ⇒ Object
readonly
Returns the value of attribute locale.
-
#rules ⇒ Object
readonly
Returns the value of attribute rules.
-
#theme ⇒ Object
readonly
Returns the value of attribute theme.
-
#title ⇒ Object
readonly
Returns the value of attribute title.
Instance Method Summary collapse
- #add_rule(name, node) ⇒ Object
-
#initialize(title: 'Grammar', theme: :auto, locale: :en) ⇒ Document
constructor
A new instance of Document.
-
#lint ⇒ Object
Returns warnings about references and redundant branches.
-
#rule_sections(max_width: nil) ⇒ Object
Returns rendered rule sections with IDs, references, SVG, and text alternatives.
- #to_html(interactive: true, index: :definition, max_width: nil, css: nil) ⇒ Object
Constructor Details
#initialize(title: 'Grammar', theme: :auto, locale: :en) ⇒ Document
Returns a new instance of Document.
12 13 14 15 16 17 18 19 20 21 |
# File 'lib/railroad_diagrams/document.rb', line 12 def initialize(title: 'Grammar', theme: :auto, locale: :en) raise InvalidArgument, 'title must be a String' unless title.is_a?(String) Theme[theme] I18n.t(:describe_truncated, locale: locale) @title = title @theme = theme @locale = locale @rules = [] end |
Instance Attribute Details
#locale ⇒ Object (readonly)
Returns the value of attribute locale.
10 11 12 |
# File 'lib/railroad_diagrams/document.rb', line 10 def locale @locale end |
#rules ⇒ Object (readonly)
Returns the value of attribute rules.
10 11 12 |
# File 'lib/railroad_diagrams/document.rb', line 10 def rules @rules end |
#theme ⇒ Object (readonly)
Returns the value of attribute theme.
10 11 12 |
# File 'lib/railroad_diagrams/document.rb', line 10 def theme @theme end |
#title ⇒ Object (readonly)
Returns the value of attribute title.
10 11 12 |
# File 'lib/railroad_diagrams/document.rb', line 10 def title @title end |
Instance Method Details
#add_rule(name, node) ⇒ Object
23 24 25 26 27 28 29 |
# File 'lib/railroad_diagrams/document.rb', line 23 def add_rule(name, node) raise InvalidArgument, 'rule name must be a nonempty String' unless name.is_a?(String) && !name.empty? raise InvalidArgument, 'rule body must be a DiagramItem' unless node.is_a?(DiagramItem) @rules << [name, node] self end |
#lint ⇒ Object
Returns warnings about references and redundant branches.
34 35 36 |
# File 'lib/railroad_diagrams/document.rb', line 34 def lint Transform::Lint.call(@rules) end |
#rule_sections(max_width: nil) ⇒ Object
Returns rendered rule sections with IDs, references, SVG, and text alternatives.
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
# File 'lib/railroad_diagrams/document.rb', line 41 def rule_sections(max_width: nil) ids = rule_ids targets = @rules.each_with_index.with_object({}) { |((name, _), index), found| found[name] ||= ids[index] } references = @rules.map do |_, node| node.each_node.grep(NonTerminal).map { |item| item.instance_variable_get(:@text) }.uniq end @rules.each_with_index.map do |(name, node), index| diagram = Marshal.load(Marshal.dump(node)) diagram.each_node do |item| next unless item.is_a?(NonTerminal) && item.instance_variable_get(:@href).nil? target = targets[item.instance_variable_get(:@text)] item.instance_variable_set(:@href, "##{target}") if target end diagram = Diagram.new(diagram) unless diagram.is_a?(Diagram) { name: name, id: ids[index], svg: diagram.to_svg(theme: @theme, locale: @locale, href_mode: :href, id_prefix: "r#{index}-", max_width: max_width), text: diagram.to_text(charset: :unicode), referenced_by: @rules.each_index.select { |source| references[source].include?(name) }.map { |source| @rules[source].first }.uniq } end end |
#to_html(interactive: true, index: :definition, max_width: nil, css: nil) ⇒ Object
66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 |
# File 'lib/railroad_diagrams/document.rb', line 66 def to_html(interactive: true, index: :definition, max_width: nil, css: nil) raise InvalidArgument, 'index must be :definition or :alphabetical' unless %i[definition alphabetical].include?(index) raise InvalidArgument, 'CSS must be a String without </style>' if css && (!css.is_a?(String) || css.match?(%r{</style}i)) sections = rule_sections(max_width: max_width) = index == :alphabetical ? sections.sort_by { |section| section[:name].downcase } : sections warnings = lint stylesheet = [Theme[@theme].css(css_variables: false), css].compact.join("\n") labels = if @locale == :ja { rules: '規則', search: '規則を検索', text: 'テキスト図', referenced_by: '参照元', warnings: '文法の警告' } else { rules: 'Rules', search: 'Search rules', text: 'Text diagram', referenced_by: 'Referenced by', warnings: 'Lint warnings' } end ERB.new(File.read(File.('templates/document.erb', __dir__))).result(binding) end |