Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

added Sass/SCSS support; added HAML eval context providing metamodel …

…access; support for logger in Server
  • Loading branch information...
commit 0ade31a8e91c30306163dc71c176ffc03a606a07 1 parent 8306977
Martin Thiede authored
4 CHANGELOG
View
@@ -30,7 +30,7 @@
* Fixed marker (cursor) positioning for editor nodes with offset
* Fixed exception in case fold control nodes are not present
-=0.x.x
+=0.2.1
-* Added support for HAML style HTML templates
+* Added support for HAML style HTML templates and stylesheets based on SASS
12 doc/concrete_developers_guide.html
View
@@ -753,13 +753,15 @@ <h3 id="_concrete_syntaxes">Concrete Syntaxes</h3><div style="clear:left"></div>
templates.html
&lt;syntax 2&gt;
style.css
- templates.html</tt></pre>
+ templates.html
+...
+&lt;syntax root dir n&gt;</tt></pre>
</div></div>
-<div class="paragraph"><p>There can be several syntax root directories (e.g. one which is deployed with your editor and one in the user&#8217;s home directory). The display name of a specific syntax is derived from the syntax directory within a root directory. The syntax directory should contain a file "templates.html" or "templates.haml" in case the syntax contains a HTML part. It should also contain a CSS file "style.css" and it may contain more resources (e.g. images) referenced from that stylesheet.</p></div>
-<div class="paragraph"><p>HTML templates may be specified in HAML format to make them more concise and readable. For this to work, <em>haml</em> needs to be installed as a gem (use "gem install haml") and the HTML templates file must be named "templates.haml".</p></div>
+<div class="paragraph"><p>There can be several syntax root directories (e.g. one which is deployed with your editor and one in the user&#8217;s home directory). The display name of a specific syntax is derived from the syntax directory within a root directory. The syntax directory should contain a file "templates.html" or "templates.haml" in case the syntax contains a HTML part. It should also contain a CSS, SASS or SCSS file and it may contain more resources (e.g. images) referenced from that stylesheet.</p></div>
+<div class="paragraph"><p>HTML templates and stylesheets may be specified in HAML and SASS or SCSS format to make them more concise and readable. For this to work, <em>haml</em> needs to be installed as a gem (use "gem install haml"), the HTML templates file must be named "templates.haml" and the SASS and SCSS filenames must end with .sass and .scss. If the server is given a <em>haml eval contect</em> object (see below) the HAML templates will evaluate in this context.</p></div>
<div class="paragraph"><p>The server will make the files in the directory of the selected syntax available via the path prefix "/syntax". It will also insert the contents of the file "template.html" in the main HTML file by replacing the placeholder comment "html templates". See below for an example.</p></div>
<h3 id="_setting_up_the_server">Setting up the Server</h3><div style="clear:left"></div>
-<div class="paragraph"><p>With a working set, data provider and syntax provider in place the server can be instantiated. As an additional argument, it needs the location of its HTML root directory. The root directory should contain a file named "editor.html" which is the main HTML file as described in the next section.</p></div>
+<div class="paragraph"><p>With a working set, data provider and syntax provider in place the server can be instantiated. As an additional argument, it needs the location of its HTML root directory. The root directory should contain a file named "editor.html" which is the main HTML file as described in the next section. A further option to the server is the HAML eval context which can be provided using the named argument <em>:hamlEvalContext</em>.</p></div>
<div class="paragraph"><p>The following example code sets up an instance of <em>Concrete::Server</em>. It reads the module names as file names from the command line and uses the RGen builtin ECore meta-metamodel as metamodel (in fact this is taken form the "mmedit" metamodel editor project). It uses the <em>Concrete::IndexBuilder</em> to derive the index metamodel and the index model and it uses a <em>Concrete::Config</em> to store the preferences in the user&#8217;s home directory.</p></div>
<div class="listingblock">
<div class="content">
@@ -1048,7 +1050,7 @@ <h2 id="_css_class_reference">CSS Class Reference</h2>
</div>
<div id="footer">
<div id="footer-text">
-Last updated 2010-06-25 11:36:59 WEDT
+Last updated 2010-06-30 08:10:12 WEDT
</div>
</div>
</body>
8 doc/concrete_developers_guide.txt
View
@@ -353,18 +353,20 @@ The workbench server supports selecting a concrete syntax from a set of availabl
<syntax 2>
style.css
templates.html
+...
+<syntax root dir n>
----
-There can be several syntax root directories (e.g. one which is deployed with your editor and one in the user's home directory). The display name of a specific syntax is derived from the syntax directory within a root directory. The syntax directory should contain a file "templates.html" or "templates.haml" in case the syntax contains a HTML part. It should also contain a CSS file "style.css" and it may contain more resources (e.g. images) referenced from that stylesheet.
+There can be several syntax root directories (e.g. one which is deployed with your editor and one in the user's home directory). The display name of a specific syntax is derived from the syntax directory within a root directory. The syntax directory should contain a file "templates.html" or "templates.haml" in case the syntax contains a HTML part. It should also contain a CSS, SASS or SCSS file and it may contain more resources (e.g. images) referenced from that stylesheet.
-HTML templates may be specified in HAML format to make them more concise and readable. For this to work, _haml_ needs to be installed as a gem (use "gem install haml") and the HTML templates file must be named "templates.haml".
+HTML templates and stylesheets may be specified in HAML and SASS or SCSS format to make them more concise and readable. For this to work, _haml_ needs to be installed as a gem (use "gem install haml"), the HTML templates file must be named "templates.haml" and the SASS and SCSS filenames must end with .sass and .scss. If the server is given a _haml eval contect_ object (see below) the HAML templates will evaluate in this context.
The server will make the files in the directory of the selected syntax available via the path prefix "/syntax". It will also insert the contents of the file "template.html" in the main HTML file by replacing the placeholder comment "html templates". See below for an example.
=== Setting up the Server ===
-With a working set, data provider and syntax provider in place the server can be instantiated. As an additional argument, it needs the location of its HTML root directory. The root directory should contain a file named "editor.html" which is the main HTML file as described in the next section.
+With a working set, data provider and syntax provider in place the server can be instantiated. As an additional argument, it needs the location of its HTML root directory. The root directory should contain a file named "editor.html" which is the main HTML file as described in the next section. A further option to the server is the HAML eval context which can be provided using the named argument _:hamlEvalContext_.
The following example code sets up an instance of _Concrete::Server_. It reads the module names as file names from the command line and uses the RGen builtin ECore meta-metamodel as metamodel (in fact this is taken form the "mmedit" metamodel editor project). It uses the _Concrete::IndexBuilder_ to derive the index metamodel and the index model and it uses a _Concrete::Config_ to store the preferences in the user's home directory.
32 lib/concrete/concrete_syntax_provider.rb
View
@@ -1,15 +1,11 @@
require 'andand'
-begin
- require 'haml'
-rescue LoadError
-end
module Concrete
class ConcreteSyntaxProvider
class ConcreteSyntax
- attr_accessor :ident, :dir, :name, :desc, :htmlTemplates, :cssStyleFile
+ attr_accessor :ident, :dir, :name, :desc
end
def initialize(configDirs, logger, config=nil)
@@ -44,43 +40,17 @@ def syntaxes
Dir.entries(cd).sort.each do |sd|
next if sd == "." || sd == ".."
syntaxDir = cd+"/"+sd
- templatesData = templatesData(syntaxDir)
- styleFile = syntaxDir + "/style.css"
- unless templatesData || File.exist?(styleFile)
- @logger.warn("Concrete syntax dir without a templates.haml (and HAML installed), templates.html or a style.css: #{syntaxDir}")
- next
- end
s = ConcreteSyntax.new
s.ident = syntaxDir.gsub("\\","/")
s.dir = syntaxDir
s.name = sd.split(/[_\W]/).collect{|w| w.capitalize}.join(" ")
s.desc = ""
- s.cssStyleFile = styleFile if File.exist?(styleFile)
- s.htmlTemplates = templatesData
result << s
end
end
result
end
- private
-
- def templatesData(syntaxDir)
- if haml && File.exist?(syntaxDir + "/templates.haml")
- engine = haml::Engine.new(File.read(syntaxDir + "/templates.haml"))
- engine.render
- elsif File.exist?(syntaxDir + "/templates.html")
- File.read(syntaxDir + "/templates.html")
- end
- end
-
- def haml
- begin
- Haml
- rescue NameError
- end
- end
-
end
end
57 lib/concrete/haml_eval_context.rb
View
@@ -0,0 +1,57 @@
+require 'rgen/ecore/ecore'
+
+module Concrete
+
+# Objects of this class are meant to be used as HAML eval context
+# Context methods provide convenient access to the metamodel
+# The metamodel is expected to be a RGen ECore metamodel
+class HamlEvalContext
+ def initialize(mm)
+ @mm = mm
+ @metaclassesByName = nil
+ end
+
+ def metaclasses
+ loadMetaclasses unless @metaclassesByName
+ @metaclassesByName.values
+ end
+
+ def metaclass(name)
+ loadMetaclasses unless @metaclassesByName
+ @metaclassesByName[name]
+ end
+
+ def metaclassFeatures(name, options={})
+ exclusions = options[:except] || []
+ if exclusions.is_a?(Array)
+ metaclass(name).eAllStructuralFeatures.reject{|f| exclusions.include?(f.name)}
+ else
+ metaclass(name).eAllStructuralFeatures.reject{|f| exclusions == f.name}
+ end
+ end
+
+ def metaclassContainments(name, options={})
+ metaclassFeatures(name, options).select{|f| f.is_a?(RGen::ECore::EReference) && f.containment}
+ end
+
+ def metaclassReferences(name, options={})
+ metaclassFeatures(name, options).select{|f| f.is_a?(RGen::ECore::EReference) && !f.containment}
+ end
+
+ def metaclassAttributes(name, options={})
+ metaclassFeatures(name, options).select{|f| f.is_a?(RGen::ECore::EAttribute)}
+ end
+
+ private
+
+ def loadMetaclasses
+ @metaclassesByName = {}
+ @mm.eAllClasses.each do |c|
+ @metaclassesByName[c.name] = c
+ end
+ end
+
+end
+
+end
+
45 lib/concrete/server.rb
View
@@ -1,4 +1,9 @@
require 'webrick'
+begin
+ require 'haml'
+ require 'sass'
+rescue LoadError
+end
module Concrete
@@ -9,6 +14,8 @@ def initialize(workingSet, dataProvider, syntaxProvider, htmlRoot, options={})
@dataProvider = dataProvider
@syntaxProvider = syntaxProvider
@htmlRoot = htmlRoot
+ @logger = options[:logger]
+ @hamlEvalContext = options[:hamlEvalContext]
@mutex = Mutex.new
@server = WEBrick::HTTPServer.new(:Port => (options[:port] || 1234))
@server.mount_proc("/") do |req, res|
@@ -27,16 +34,15 @@ def start
def handleRequest(req, res)
if req.path == "/"
editorHtml = File.read(@htmlRoot+"/editor.html")
- editorHtml.sub!(/<!--\s+html templates\s+-->/, @syntaxProvider.selectedSyntax.htmlTemplates) if @syntaxProvider.andand.selectedSyntax.andand.htmlTemplates
+ templatesData = htmlTemplatesData(@syntaxProvider.selectedSyntax.dir) if @syntaxProvider.selectedSyntax
+ editorHtml.sub!(/<!--\s+html templates\s+-->/, templatesData) if templatesData
res.body = editorHtml
elsif req.path =~ /^\/html\/(.*)/
File.open(@htmlRoot+"/"+$1, "rb") do |f|
res.body = f.read
end
elsif req.path =~ /^\/syntax\/(.*)/ && @syntaxProvider.selectedSyntax
- File.open(@syntaxProvider.selectedSyntax.dir+"/"+$1, "rb") do |f|
- res.body = f.read
- end
+ res.body = syntaxFileData(@syntaxProvider.selectedSyntax.dir+"/"+$1)
elsif req.path =~ /^\/concrete\/(.*)/
File.open(File.dirname(__FILE__)+"/../../"+$1, "rb") do |f|
res.body = f.read
@@ -85,7 +91,36 @@ def handleRequest(req, res)
# error
end
end
-
+
+ def syntaxFileData(fileName)
+ if haveHaml? && fileName =~ /(\.sass|\.scss)$/
+ Sass::Engine.new(File.read(fileName)).render
+ else
+ File.open(fileName, "rb") do |f|
+ f.read
+ end
+ end
+ end
+
+ def htmlTemplatesData(syntaxDir)
+ if haveHaml? && File.exist?(syntaxDir + "/templates.haml")
+ templatesFile = syntaxDir + "/templates.haml"
+ @logger.info("Using HAML templates file #{templatesFile}") if @logger
+ engine = Haml::Engine.new(File.read(templatesFile))
+ engine.render(@hamlEvalContext || Object.new)
+ elsif File.exist?(syntaxDir + "/templates.html")
+ templatesFile = syntaxDir + "/templates.html"
+ @logger.info("Using HTML templates file #{templatesFile}") if @logger
+ File.read(templatesFile)
+ end
+ end
+
+ def haveHaml?
+ begin
+ Haml
+ rescue NameError
+ end
+ end
end
end
46 test/concrete_syntax_provider_test.rb
View
@@ -65,10 +65,12 @@ def test_syntaxes_no_syntaxes
def test_syntaxes_empty_syntax
logger = LoggerMock.new
sp = Concrete::ConcreteSyntaxProvider.new([TestDir+"/syntaxDir1"], logger)
- assert_equal [], sp.syntaxes
- assert_equal 1, logger.messages.size
- assert_match /WARN: Concrete syntax dir without a templates/, logger.messages.first
- assert_equal '{ "syntaxes": [], "selected": "" }', sp.syntaxesAsJson
+ assert_equal 1, sp.syntaxes.size
+ assert_equal "Empty Syntax", sp.syntaxes.first.name
+ assert_equal [], logger.messages
+ assert_equal '{ "syntaxes": [' +
+ '{ "ident": "'+TestDir+'/syntaxDir1/empty_syntax", "name": "Empty Syntax" }' +
+ '], "selected": "" }', sp.syntaxesAsJson
end
def test_syntaxes_common
@@ -77,30 +79,13 @@ def test_syntaxes_common
syntaxes = sp.syntaxes
assert_equal 1, syntaxes.size
assert_equal "First Syntax", syntaxes.first.name
- assert_equal "./concrete_syntax_provider_test/syntaxDir2/first_syntax/style.css", syntaxes.first.cssStyleFile
- assert_equal "./concrete_syntax_provider_test/syntaxDir2/first_syntax", syntaxes.first.ident
- assert_nil syntaxes.first.htmlTemplates
+ assert_equal TestDir+"/syntaxDir2/first_syntax", syntaxes.first.ident
assert_equal '{ "syntaxes": [' +
- '{ "ident": "./concrete_syntax_provider_test/syntaxDir2/first_syntax", "name": "First Syntax" }' +
+ '{ "ident": "'+TestDir+'/syntaxDir2/first_syntax", "name": "First Syntax" }' +
'], "selected": "" }', sp.syntaxesAsJson
assert_equal [], logger.messages
end
- def test_syntaxes_templates
- logger = LoggerMock.new
- sp = Concrete::ConcreteSyntaxProvider.new([TestDir+"/syntaxDir3"], logger)
- syntaxes = sp.syntaxes
- if haveHaml?
- assert_equal 2, syntaxes.size
- assert_equal "<p>Haml code!</p>", syntaxes.find{|s| s.name == "Haml Syntax"}.htmlTemplates.strip
- assert_equal "<div>Template Content</div>", syntaxes.find{|s| s.name == "Html Syntax"}.htmlTemplates.strip
- else
- assert_equal 1, syntaxes.size
- assert_equal "<div>Template Content</div>", syntaxes.first.htmlTemplates.strip
- assert logger.messages.any?{|m| m =~ /Concrete syntax dir without.*and HAML installed/}
- end
- end
-
def test_selectSyntax_no_syntax
logger = LoggerMock.new
sp = Concrete::ConcreteSyntaxProvider.new([], logger)
@@ -117,14 +102,14 @@ def test_selectSyntax_no_config
sp.selectSyntax("dummy")
end
assert_equal "First Syntax", sp.selectedSyntax.name
- sp.selectSyntax("./concrete_syntax_provider_test/syntaxDir3/haml_syntax")
+ sp.selectSyntax(TestDir+"/syntaxDir3/haml_syntax")
assert_equal "Haml Syntax", sp.selectedSyntax.name
end
def test_selectSyntax_load_config
logger = LoggerMock.new
config = ConfigMock.new
- config.values["concrete_syntax"] = "./concrete_syntax_provider_test/syntaxDir3/haml_syntax"
+ config.values["concrete_syntax"] = TestDir+"/syntaxDir3/haml_syntax"
sp = Concrete::ConcreteSyntaxProvider.new([TestDir+"/syntaxDir2", TestDir+"/syntaxDir3"], logger, config)
assert_equal "Haml Syntax", sp.selectedSyntax.name
end
@@ -135,15 +120,8 @@ def test_selectSyntax_store_config
sp = Concrete::ConcreteSyntaxProvider.new([TestDir+"/syntaxDir2", TestDir+"/syntaxDir3"], logger, config)
sp.selectSyntax("dummy")
assert_equal({}, config.values)
- sp.selectSyntax("./concrete_syntax_provider_test/syntaxDir3/haml_syntax" )
- assert_equal({"concrete_syntax" => "./concrete_syntax_provider_test/syntaxDir3/haml_syntax" }, config.values)
- end
-
- def haveHaml?
- begin
- Haml
- rescue NameError
- end
+ sp.selectSyntax(TestDir+"/syntaxDir3/haml_syntax" )
+ assert_equal({"concrete_syntax" => TestDir+"/syntaxDir3/haml_syntax" }, config.values)
end
end
1  test/concrete_test.rb
View
@@ -3,4 +3,5 @@
require 'metamodel_test'
require 'working_set_test'
require 'concrete_syntax_provider_test'
+require 'haml_eval_context_test'
46 test/haml_eval_context_test.rb
View
@@ -0,0 +1,46 @@
+$:.unshift File.join(File.dirname(__FILE__),"..","lib")
+
+require 'test/unit'
+require 'rgen/environment'
+require 'rgen/array_extensions'
+require 'rgen/ecore/ecore'
+require 'concrete/haml_eval_context'
+begin
+ require 'haml'
+rescue LoadError
+end
+
+class HamlEvalContextTest < Test::Unit::TestCase
+
+ def test_simple
+ return unless haveHaml?
+ context = Concrete::HamlEvalContext.new(RGen::ECore.ecore)
+ engine = Haml::Engine.new("= metaclass('EClass').name")
+ assert_equal "EClass\n", engine.render(context)
+ engine = Haml::Engine.new("= metaclasses.size")
+ assert_equal "18\n", engine.render(context)
+ engine = Haml::Engine.new("= metaclassFeatures('EEnum').size")
+ assert_equal "8\n", engine.render(context)
+ engine = Haml::Engine.new("= metaclassContainments('EEnum').size")
+ assert_equal "2\n", engine.render(context)
+ engine = Haml::Engine.new("= metaclassReferences('EEnum').size")
+ assert_equal "1\n", engine.render(context)
+ engine = Haml::Engine.new("= metaclassAttributes('EEnum').size")
+ assert_equal "5\n", engine.render(context)
+ engine = Haml::Engine.new("= metaclassAttributes('EEnum', :except => ['name']).size")
+ assert_equal "4\n", engine.render(context)
+ engine = Haml::Engine.new("= metaclassAttributes('EEnum', :except => 'name').size")
+ assert_equal "4\n", engine.render(context)
+ engine = Haml::Engine.new("= metaclassAttributes('EEnum', :except => 'namex').size")
+ assert_equal "5\n", engine.render(context)
+ end
+
+ def haveHaml?
+ begin
+ Haml
+ rescue NameError
+ end
+ end
+
+end
+
Please sign in to comment.
Something went wrong with that request. Please try again.