Skip to content

Commit

Permalink
Add Mason lexer (#838)
Browse files Browse the repository at this point in the history
This commit adds a lexer for the Mason framework.
  • Loading branch information
miparnisari authored and pyrmont committed Jul 19, 2019
1 parent 1842a0d commit d866778
Show file tree
Hide file tree
Showing 6 changed files with 398 additions and 0 deletions.
22 changes: 22 additions & 0 deletions lib/rouge/demos/mason
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<%doc>
This is a mason component.
# This is a comment.
</%doc>

<%args>
$color # this argument is required!
$size => 20 # default size
$country => undef # this argument is optional, default value is 'undef'
@items => (1, 2, 'something else')
%pairs => (name => "John", age => 29)
</%args>

% # A random block of Perl code
<%perl>
my @people = ('mary' 'john' 'pete' 'david');
</%perl>

% # Note how each line of code begins with the mandatory %
% foreach my $person (@people) {
Name: <% $person %>
% }
4 changes: 4 additions & 0 deletions lib/rouge/guessers/disambiguation.rb
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,11 @@ def match?(filename)
next Mathematica if contains?('(*')
next Mathematica if contains?(':=')

next Mason if matches?(/<%(def|method|text|doc|args|flags|attr|init|once|shared|perl|cleanup|filter)([^>]*)(>)/)

next Matlab if matches?(/^\s*?%/)

next Mason if matches? %r!(</?%|<&)!
end

disambiguate '*.php' do
Expand Down
116 changes: 116 additions & 0 deletions lib/rouge/lexers/mason.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
# -*- coding: utf-8 -*- #
# frozen_string_literal: true

module Rouge
module Lexers
class Mason < TemplateLexer
title 'Mason'
desc 'The HTML::Mason framework (https://metacpan.org/pod/HTML::Mason)'
tag 'mason'
filenames '*.mi', '*.mc', '*.mas', '*.m', '*.mhtml', '*.mcomp', 'autohandler', 'dhandler'
mimetypes 'text/x-mason', 'application/x-mason'

def initialize(*)
super
@perl = Perl.new
end

def self.detect?(text)
return false if text.doctype?(/((?:ht|x)ml)/)
return true if text.doctype?
end

# Note: If you add a tag in the lines below, you also need to modify "disambiguate '*.m'" in file disambiguation.rb
TEXT_BLOCKS = %w(text doc)
PERL_BLOCKS = %w(args flags attr init once shared perl cleanup filter strings general_media shared_vars)
COMPONENTS = %w(def method)

state :root do
mixin :mason_tags
end

state :mason_tags do
rule %r/\s+/, Text::Whitespace

rule %r/<%(#{TEXT_BLOCKS.join('|')})>/oi, Comment::Preproc, :text_block

rule %r/<%(#{PERL_BLOCKS.join('|')})>/oi, Comment::Preproc, :perl_block

rule %r/(<%(#{COMPONENTS.join('|')}))([^>]*)(>)/oi do |m|
token Comment::Preproc, m[1]
token Name, m[3]
token Comment::Preproc, m[4]
push :component_block
end

# perl line
rule %r/^(%)(.*)$/ do |m|
token Comment::Preproc, m[1]
delegate @perl, m[2]
end

# start of component call
rule %r/<%/, Comment::Preproc, :component_call

# start of component with content
rule %r/<&\|/ do
token Comment::Preproc
push :component_with_content
push :component_sub
end

# start of component substitution
rule %r/<&/, Comment::Preproc, :component_sub

# fallback to HTML until a mason tag is encountered
rule(/(.+?)(?=(<\/?&|<\/?%|^%|^#))/m) { delegate parent }

# if we get here, there's no more mason tags, so we parse the rest of the doc as HTML
rule(/.+/m) { delegate parent }
end

state :perl_block do
rule %r/<\/%(#{PERL_BLOCKS.join('|')})>/oi, Comment::Preproc, :pop!
rule %r/\s+/, Text::Whitespace
rule %r/^(#.*)$/, Comment
rule(/(.*?[^"])(?=<\/%)/m) { delegate @perl }
end

state :text_block do
rule %r/<\/%(#{TEXT_BLOCKS.join('|')})>/oi, Comment::Preproc, :pop!
rule %r/\s+/, Text::Whitespace
rule %r/^(#.*)$/, Comment
rule %r/(.*?[^"])(?=<\/%)/m, Comment
end

state :component_block do
rule %r/<\/%(#{COMPONENTS.join('|')})>/oi, Comment::Preproc, :pop!
rule %r/\s+/, Text::Whitespace
rule %r/^(#.*)$/, Comment
mixin :mason_tags
end

state :component_with_content do
rule %r/<\/&>/ do
token Comment::Preproc
pop!
end

mixin :mason_tags
end

state :component_sub do
rule %r/&>/, Comment::Preproc, :pop!

rule(/(.*?)(?=&>)/m) { delegate @perl }
end

state :component_call do
rule %r/%>/, Comment::Preproc, :pop!

rule(/(.*?)(?=%>)/m) { delegate @perl }
end
end
end
end

43 changes: 43 additions & 0 deletions spec/lexers/mason_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# -*- coding: utf-8 -*- #

describe Rouge::Lexers::Mason do
let(:subject) { Rouge::Lexers::Mason.new }

describe 'guessing' do
include Support::Guessing

it 'guesses by filename' do
assert_guess :filename => 'foo.mas'
assert_guess :filename => 'foo.mi'
assert_guess :filename => 'foo.mc'
assert_guess :filename => 'foo.mhtml'
assert_guess :filename => 'foo.mcomp'
assert_guess :filename => 'autohandler'
assert_guess :filename => 'dhandler'
end

it 'guesses by mimetype' do
assert_guess :mimetype => 'text/x-mason'
assert_guess :mimetype => 'application/x-mason'
end

it 'guesses by source' do
assert_guess :filename => 'foo.m', :source => <<-eos
<%doc>
This is a mason component.
</%doc>
eos

end

it 'guesses by source when using component calls' do
assert_guess :filename => 'foo.m', :source => <<-eos
<& 'SELF:component' &>
eos

end

end
end
18 changes: 18 additions & 0 deletions spec/lexers/matlab_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,24 @@
assert_guess :mimetype => 'text/x-matlab'
assert_guess :mimetype => 'application/x-matlab'
end

it 'guesses by source' do
assert_guess :filename => 'foo.m', :source => <<-eos
function ImageGaborPhase(TFType,pkt,ell,titlestr)
% ImageGaborPhase -- Time-Frequency Display with congruent rectangles
eos
end

it 'guesses by source' do
assert_guess :filename => 'foo.m', :source => <<-eos
methods
function obj = GaussianBlur(sigma, img_size, edges)
%GAUSSIANBLUR Create Gaussian Blur filter object
end
end
eos
end
end
end

Loading

0 comments on commit d866778

Please sign in to comment.