inversion 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data.tar.gz.sig +2 -0
 - data/.gemtest +0 -0
 - data/ChangeLog +836 -0
 - data/History.md +4 -0
 - data/Manifest.txt +74 -0
 - data/README.rdoc +171 -0
 - data/Rakefile +55 -0
 - data/bin/inversion +276 -0
 - data/lib/inversion.rb +98 -0
 - data/lib/inversion/exceptions.rb +21 -0
 - data/lib/inversion/mixins.rb +236 -0
 - data/lib/inversion/monkeypatches.rb +20 -0
 - data/lib/inversion/renderstate.rb +337 -0
 - data/lib/inversion/sinatra.rb +35 -0
 - data/lib/inversion/template.rb +250 -0
 - data/lib/inversion/template/attrtag.rb +120 -0
 - data/lib/inversion/template/calltag.rb +16 -0
 - data/lib/inversion/template/codetag.rb +164 -0
 - data/lib/inversion/template/commenttag.rb +54 -0
 - data/lib/inversion/template/conditionaltag.rb +49 -0
 - data/lib/inversion/template/configtag.rb +60 -0
 - data/lib/inversion/template/containertag.rb +45 -0
 - data/lib/inversion/template/elsetag.rb +62 -0
 - data/lib/inversion/template/elsiftag.rb +49 -0
 - data/lib/inversion/template/endtag.rb +55 -0
 - data/lib/inversion/template/escapetag.rb +26 -0
 - data/lib/inversion/template/fortag.rb +120 -0
 - data/lib/inversion/template/iftag.rb +69 -0
 - data/lib/inversion/template/importtag.rb +70 -0
 - data/lib/inversion/template/includetag.rb +51 -0
 - data/lib/inversion/template/node.rb +102 -0
 - data/lib/inversion/template/parser.rb +297 -0
 - data/lib/inversion/template/pptag.rb +28 -0
 - data/lib/inversion/template/publishtag.rb +72 -0
 - data/lib/inversion/template/subscribetag.rb +88 -0
 - data/lib/inversion/template/tag.rb +150 -0
 - data/lib/inversion/template/textnode.rb +43 -0
 - data/lib/inversion/template/unlesstag.rb +60 -0
 - data/lib/inversion/template/uriencodetag.rb +30 -0
 - data/lib/inversion/template/yieldtag.rb +51 -0
 - data/lib/inversion/tilt.rb +82 -0
 - data/lib/inversion/utils.rb +235 -0
 - data/spec/data/sinatra/hello.inversion +1 -0
 - data/spec/inversion/mixins_spec.rb +177 -0
 - data/spec/inversion/monkeypatches_spec.rb +35 -0
 - data/spec/inversion/renderstate_spec.rb +291 -0
 - data/spec/inversion/sinatra_spec.rb +59 -0
 - data/spec/inversion/template/attrtag_spec.rb +216 -0
 - data/spec/inversion/template/calltag_spec.rb +30 -0
 - data/spec/inversion/template/codetag_spec.rb +51 -0
 - data/spec/inversion/template/commenttag_spec.rb +84 -0
 - data/spec/inversion/template/configtag_spec.rb +105 -0
 - data/spec/inversion/template/containertag_spec.rb +54 -0
 - data/spec/inversion/template/elsetag_spec.rb +105 -0
 - data/spec/inversion/template/elsiftag_spec.rb +87 -0
 - data/spec/inversion/template/endtag_spec.rb +78 -0
 - data/spec/inversion/template/escapetag_spec.rb +59 -0
 - data/spec/inversion/template/fortag_spec.rb +98 -0
 - data/spec/inversion/template/iftag_spec.rb +241 -0
 - data/spec/inversion/template/importtag_spec.rb +106 -0
 - data/spec/inversion/template/includetag_spec.rb +108 -0
 - data/spec/inversion/template/node_spec.rb +81 -0
 - data/spec/inversion/template/parser_spec.rb +170 -0
 - data/spec/inversion/template/pptag_spec.rb +51 -0
 - data/spec/inversion/template/publishtag_spec.rb +69 -0
 - data/spec/inversion/template/subscribetag_spec.rb +60 -0
 - data/spec/inversion/template/tag_spec.rb +97 -0
 - data/spec/inversion/template/textnode_spec.rb +86 -0
 - data/spec/inversion/template/unlesstag_spec.rb +84 -0
 - data/spec/inversion/template/uriencodetag_spec.rb +49 -0
 - data/spec/inversion/template/yieldtag_spec.rb +54 -0
 - data/spec/inversion/template_spec.rb +269 -0
 - data/spec/inversion/tilt_spec.rb +47 -0
 - data/spec/inversion_spec.rb +95 -0
 - data/spec/lib/constants.rb +9 -0
 - data/spec/lib/helpers.rb +160 -0
 - metadata +316 -0
 - metadata.gz.sig +0 -0
 
    
        data/History.md
    ADDED
    
    
    
        data/Manifest.txt
    ADDED
    
    | 
         @@ -0,0 +1,74 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            ChangeLog
         
     | 
| 
      
 2 
     | 
    
         
            +
            History.md
         
     | 
| 
      
 3 
     | 
    
         
            +
            Manifest.txt
         
     | 
| 
      
 4 
     | 
    
         
            +
            README.rdoc
         
     | 
| 
      
 5 
     | 
    
         
            +
            Rakefile
         
     | 
| 
      
 6 
     | 
    
         
            +
            bin/inversion
         
     | 
| 
      
 7 
     | 
    
         
            +
            lib/inversion.rb
         
     | 
| 
      
 8 
     | 
    
         
            +
            lib/inversion/exceptions.rb
         
     | 
| 
      
 9 
     | 
    
         
            +
            lib/inversion/mixins.rb
         
     | 
| 
      
 10 
     | 
    
         
            +
            lib/inversion/monkeypatches.rb
         
     | 
| 
      
 11 
     | 
    
         
            +
            lib/inversion/renderstate.rb
         
     | 
| 
      
 12 
     | 
    
         
            +
            lib/inversion/sinatra.rb
         
     | 
| 
      
 13 
     | 
    
         
            +
            lib/inversion/template.rb
         
     | 
| 
      
 14 
     | 
    
         
            +
            lib/inversion/template/attrtag.rb
         
     | 
| 
      
 15 
     | 
    
         
            +
            lib/inversion/template/calltag.rb
         
     | 
| 
      
 16 
     | 
    
         
            +
            lib/inversion/template/codetag.rb
         
     | 
| 
      
 17 
     | 
    
         
            +
            lib/inversion/template/commenttag.rb
         
     | 
| 
      
 18 
     | 
    
         
            +
            lib/inversion/template/conditionaltag.rb
         
     | 
| 
      
 19 
     | 
    
         
            +
            lib/inversion/template/configtag.rb
         
     | 
| 
      
 20 
     | 
    
         
            +
            lib/inversion/template/containertag.rb
         
     | 
| 
      
 21 
     | 
    
         
            +
            lib/inversion/template/elsetag.rb
         
     | 
| 
      
 22 
     | 
    
         
            +
            lib/inversion/template/elsiftag.rb
         
     | 
| 
      
 23 
     | 
    
         
            +
            lib/inversion/template/endtag.rb
         
     | 
| 
      
 24 
     | 
    
         
            +
            lib/inversion/template/escapetag.rb
         
     | 
| 
      
 25 
     | 
    
         
            +
            lib/inversion/template/fortag.rb
         
     | 
| 
      
 26 
     | 
    
         
            +
            lib/inversion/template/iftag.rb
         
     | 
| 
      
 27 
     | 
    
         
            +
            lib/inversion/template/importtag.rb
         
     | 
| 
      
 28 
     | 
    
         
            +
            lib/inversion/template/includetag.rb
         
     | 
| 
      
 29 
     | 
    
         
            +
            lib/inversion/template/node.rb
         
     | 
| 
      
 30 
     | 
    
         
            +
            lib/inversion/template/parser.rb
         
     | 
| 
      
 31 
     | 
    
         
            +
            lib/inversion/template/pptag.rb
         
     | 
| 
      
 32 
     | 
    
         
            +
            lib/inversion/template/publishtag.rb
         
     | 
| 
      
 33 
     | 
    
         
            +
            lib/inversion/template/subscribetag.rb
         
     | 
| 
      
 34 
     | 
    
         
            +
            lib/inversion/template/tag.rb
         
     | 
| 
      
 35 
     | 
    
         
            +
            lib/inversion/template/textnode.rb
         
     | 
| 
      
 36 
     | 
    
         
            +
            lib/inversion/template/unlesstag.rb
         
     | 
| 
      
 37 
     | 
    
         
            +
            lib/inversion/template/uriencodetag.rb
         
     | 
| 
      
 38 
     | 
    
         
            +
            lib/inversion/template/yieldtag.rb
         
     | 
| 
      
 39 
     | 
    
         
            +
            lib/inversion/tilt.rb
         
     | 
| 
      
 40 
     | 
    
         
            +
            lib/inversion/utils.rb
         
     | 
| 
      
 41 
     | 
    
         
            +
            spec/data/sinatra/hello.inversion
         
     | 
| 
      
 42 
     | 
    
         
            +
            spec/inversion/mixins_spec.rb
         
     | 
| 
      
 43 
     | 
    
         
            +
            spec/inversion/monkeypatches_spec.rb
         
     | 
| 
      
 44 
     | 
    
         
            +
            spec/inversion/renderstate_spec.rb
         
     | 
| 
      
 45 
     | 
    
         
            +
            spec/inversion/sinatra_spec.rb
         
     | 
| 
      
 46 
     | 
    
         
            +
            spec/inversion/template/attrtag_spec.rb
         
     | 
| 
      
 47 
     | 
    
         
            +
            spec/inversion/template/calltag_spec.rb
         
     | 
| 
      
 48 
     | 
    
         
            +
            spec/inversion/template/codetag_spec.rb
         
     | 
| 
      
 49 
     | 
    
         
            +
            spec/inversion/template/commenttag_spec.rb
         
     | 
| 
      
 50 
     | 
    
         
            +
            spec/inversion/template/configtag_spec.rb
         
     | 
| 
      
 51 
     | 
    
         
            +
            spec/inversion/template/containertag_spec.rb
         
     | 
| 
      
 52 
     | 
    
         
            +
            spec/inversion/template/elsetag_spec.rb
         
     | 
| 
      
 53 
     | 
    
         
            +
            spec/inversion/template/elsiftag_spec.rb
         
     | 
| 
      
 54 
     | 
    
         
            +
            spec/inversion/template/endtag_spec.rb
         
     | 
| 
      
 55 
     | 
    
         
            +
            spec/inversion/template/escapetag_spec.rb
         
     | 
| 
      
 56 
     | 
    
         
            +
            spec/inversion/template/fortag_spec.rb
         
     | 
| 
      
 57 
     | 
    
         
            +
            spec/inversion/template/iftag_spec.rb
         
     | 
| 
      
 58 
     | 
    
         
            +
            spec/inversion/template/importtag_spec.rb
         
     | 
| 
      
 59 
     | 
    
         
            +
            spec/inversion/template/includetag_spec.rb
         
     | 
| 
      
 60 
     | 
    
         
            +
            spec/inversion/template/node_spec.rb
         
     | 
| 
      
 61 
     | 
    
         
            +
            spec/inversion/template/parser_spec.rb
         
     | 
| 
      
 62 
     | 
    
         
            +
            spec/inversion/template/pptag_spec.rb
         
     | 
| 
      
 63 
     | 
    
         
            +
            spec/inversion/template/publishtag_spec.rb
         
     | 
| 
      
 64 
     | 
    
         
            +
            spec/inversion/template/subscribetag_spec.rb
         
     | 
| 
      
 65 
     | 
    
         
            +
            spec/inversion/template/tag_spec.rb
         
     | 
| 
      
 66 
     | 
    
         
            +
            spec/inversion/template/textnode_spec.rb
         
     | 
| 
      
 67 
     | 
    
         
            +
            spec/inversion/template/unlesstag_spec.rb
         
     | 
| 
      
 68 
     | 
    
         
            +
            spec/inversion/template/uriencodetag_spec.rb
         
     | 
| 
      
 69 
     | 
    
         
            +
            spec/inversion/template/yieldtag_spec.rb
         
     | 
| 
      
 70 
     | 
    
         
            +
            spec/inversion/template_spec.rb
         
     | 
| 
      
 71 
     | 
    
         
            +
            spec/inversion/tilt_spec.rb
         
     | 
| 
      
 72 
     | 
    
         
            +
            spec/inversion_spec.rb
         
     | 
| 
      
 73 
     | 
    
         
            +
            spec/lib/constants.rb
         
     | 
| 
      
 74 
     | 
    
         
            +
            spec/lib/helpers.rb
         
     | 
    
        data/README.rdoc
    ADDED
    
    | 
         @@ -0,0 +1,171 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            = inversion
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            * http://deveiate.org/projects/Inversion
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            == Description
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
            Inversion is a templating system for Ruby. It uses the "Inversion of Control" principle to decouple
         
     | 
| 
      
 9 
     | 
    
         
            +
            the contents and structure of the template from the code that uses it, making it easier to use,
         
     | 
| 
      
 10 
     | 
    
         
            +
            test-friendly, and clean.
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
            === Details
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
            Inversion, like most other templating systems, works by giving you a way of defining the static
         
     | 
| 
      
 16 
     | 
    
         
            +
            parts of your output, and then letting you combine that at a later point with the dynamic parts:
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
            Create the template and use it to render an exciting message:
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
            	tmpl = Inversion::Template.new( "Hello, <?attr name ?>!" )
         
     | 
| 
      
 21 
     | 
    
         
            +
            	tmpl.name = "World"
         
     | 
| 
      
 22 
     | 
    
         
            +
            	puts tmpl.render
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
            The <tt><?attr name ?></tt> tag defines the _name_ accessor on the template object, the value of
         
     | 
| 
      
 25 
     | 
    
         
            +
            which is substituted for any occurrences of +name+ in the template:
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
                Hello, World!
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
            This by itself isn't fantastically useful, but it does illustrate one of the ways in which Inversion
         
     | 
| 
      
 30 
     | 
    
         
            +
            is different: the program and the template share data through an API, instead of through a complex
         
     | 
| 
      
 31 
     | 
    
         
            +
            data structure, which establishes a clear delineation between what responsibility is the program's
         
     | 
| 
      
 32 
     | 
    
         
            +
            and which is the template's. The program doesn't have to know how the view uses the data it's given,
         
     | 
| 
      
 33 
     | 
    
         
            +
            and tests of the controller can substitute a Mock Object for the template to test the interaction
         
     | 
| 
      
 34 
     | 
    
         
            +
            between the two instead of having to match patterns in the eventual output like an integration test.
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
            You can also interact with the values set in the template:
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
                Name: <?attr employee.full_name ?>
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
            This will call the +#full_name+ method on whatever is set as the +employee+ attribute when 
         
     | 
| 
      
 41 
     | 
    
         
            +
            rendered, and the result will take the place of the tag.
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
            Inversion also comes with a collection of other tags that provide flow control, exception-handling,
         
     | 
| 
      
 44 
     | 
    
         
            +
            etc.
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
            Here's a slightly more complex example: Say we have a layout template that contains all the
         
     | 
| 
      
 47 
     | 
    
         
            +
            boilerplate, navigation, etc. for the site, and then an `<?attr body ?>` somewhere in the content
         
     | 
| 
      
 48 
     | 
    
         
            +
            area for the content specific to each view:
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
                layout = Inversion::Template.load( 'templates/layout.tmpl' )
         
     | 
| 
      
 51 
     | 
    
         
            +
             
     | 
| 
      
 52 
     | 
    
         
            +
            Then there's a view template that displays a bulleted list of article titles:
         
     | 
| 
      
 53 
     | 
    
         
            +
             
         
     | 
| 
      
 54 
     | 
    
         
            +
                <!-- articlelist.tmpl -->
         
     | 
| 
      
 55 
     | 
    
         
            +
                <section id="articles">
         
     | 
| 
      
 56 
     | 
    
         
            +
                  <ul>
         
     | 
| 
      
 57 
     | 
    
         
            +
                  <?for article in articles ?>
         
     | 
| 
      
 58 
     | 
    
         
            +
                    <li><?call article.title ?></li>
         
     | 
| 
      
 59 
     | 
    
         
            +
                  <?end for ?>
         
     | 
| 
      
 60 
     | 
    
         
            +
                  </ul>
         
     | 
| 
      
 61 
     | 
    
         
            +
                </section>
         
     | 
| 
      
 62 
     | 
    
         
            +
             
     | 
| 
      
 63 
     | 
    
         
            +
            Loading this template results in a Ruby object whose API contains one method: `#articles`. To render
         
     | 
| 
      
 64 
     | 
    
         
            +
            the view, we just call that accessor with instances of an `Article` domain class we defined
         
     | 
| 
      
 65 
     | 
    
         
            +
            elsewhere, and then drop the 'alist' template into the layout and render them:
         
     | 
| 
      
 66 
     | 
    
         
            +
             
     | 
| 
      
 67 
     | 
    
         
            +
                alist = Inversion::Template.load( 'templates/alist.tmpl' )
         
     | 
| 
      
 68 
     | 
    
         
            +
                alist.articles = Articles.latest( 10 )
         
     | 
| 
      
 69 
     | 
    
         
            +
                
         
     | 
| 
      
 70 
     | 
    
         
            +
                layout.body = alist
         
     | 
| 
      
 71 
     | 
    
         
            +
                puts layout.render
         
     | 
| 
      
 72 
     | 
    
         
            +
             
     | 
| 
      
 73 
     | 
    
         
            +
            The `for` tag in the alist will iterate over the enumerable Articles and generate an `<li>` for each
         
     | 
| 
      
 74 
     | 
    
         
            +
            one. The resulting template object will be set as the body of the layout template, and stringified
         
     | 
| 
      
 75 
     | 
    
         
            +
            when the enclosing template is rendered. Templates can be nested this way as deeply as you like.
         
     | 
| 
      
 76 
     | 
    
         
            +
             
     | 
| 
      
 77 
     | 
    
         
            +
             
     | 
| 
      
 78 
     | 
    
         
            +
            === Tags To Implement
         
     | 
| 
      
 79 
     | 
    
         
            +
             
     | 
| 
      
 80 
     | 
    
         
            +
            * <?prettyprint «attr/methodchain» ?>
         
     | 
| 
      
 81 
     | 
    
         
            +
             
     | 
| 
      
 82 
     | 
    
         
            +
            * <?render «attr/methodchain» AS «identifier» IN «template path» ?>
         
     | 
| 
      
 83 
     | 
    
         
            +
             
     | 
| 
      
 84 
     | 
    
         
            +
             
     | 
| 
      
 85 
     | 
    
         
            +
            === Tags Implemented
         
     | 
| 
      
 86 
     | 
    
         
            +
             
     | 
| 
      
 87 
     | 
    
         
            +
            * <?attr?>
         
     | 
| 
      
 88 
     | 
    
         
            +
            * <?call?>
         
     | 
| 
      
 89 
     | 
    
         
            +
            * <?comment?>…<?end?>
         
     | 
| 
      
 90 
     | 
    
         
            +
            * <?for obj, i in attr.each_with_index ?>
         
     | 
| 
      
 91 
     | 
    
         
            +
              <?end?>
         
     | 
| 
      
 92 
     | 
    
         
            +
            * <?config
         
     | 
| 
      
 93 
     | 
    
         
            +
            	  escaping: 'html'
         
     | 
| 
      
 94 
     | 
    
         
            +
            	  ignore_unknown_tags: false
         
     | 
| 
      
 95 
     | 
    
         
            +
              ?>
         
     | 
| 
      
 96 
     | 
    
         
            +
            * <?include other_template.tmpl ?>
         
     | 
| 
      
 97 
     | 
    
         
            +
            * <?escape obj.some_method ?>
         
     | 
| 
      
 98 
     | 
    
         
            +
            * <?urlencode obj.some_method ?>
         
     | 
| 
      
 99 
     | 
    
         
            +
            * <?pp obj ?>
         
     | 
| 
      
 100 
     | 
    
         
            +
            * <?if obj.some_method ?>…<?elsif otherobj.some_method ?>…<?else?>…<?end?>
         
     | 
| 
      
 101 
     | 
    
         
            +
            * <?unless obj.some_method ?>..<?end ?>
         
     | 
| 
      
 102 
     | 
    
         
            +
            * <?import attrname ?>
         
     | 
| 
      
 103 
     | 
    
         
            +
            * <?publish identifier ?>...<?end publish ?>
         
     | 
| 
      
 104 
     | 
    
         
            +
            * <?subscribe identifier ?>
         
     | 
| 
      
 105 
     | 
    
         
            +
            * <?timedelta obj.time_method ?>
         
     | 
| 
      
 106 
     | 
    
         
            +
            * <?yield ?>
         
     | 
| 
      
 107 
     | 
    
         
            +
            * <?default attribute to value ?>
         
     | 
| 
      
 108 
     | 
    
         
            +
            * <?begin ?>…<?rescue ?>…<?end?>
         
     | 
| 
      
 109 
     | 
    
         
            +
             
     | 
| 
      
 110 
     | 
    
         
            +
             
     | 
| 
      
 111 
     | 
    
         
            +
            == References
         
     | 
| 
      
 112 
     | 
    
         
            +
             
     | 
| 
      
 113 
     | 
    
         
            +
            * Inversion of Control: http://en.wikipedia.org/wiki/Inversion_of_control
         
     | 
| 
      
 114 
     | 
    
         
            +
            * Passive View: http://martinfowler.com/eaaDev/PassiveScreen.html
         
     | 
| 
      
 115 
     | 
    
         
            +
            * Supervising Controller: http://martinfowler.com/eaaDev/SupervisingPresenter.html
         
     | 
| 
      
 116 
     | 
    
         
            +
             
     | 
| 
      
 117 
     | 
    
         
            +
             
     | 
| 
      
 118 
     | 
    
         
            +
            == Installation
         
     | 
| 
      
 119 
     | 
    
         
            +
             
     | 
| 
      
 120 
     | 
    
         
            +
                gem install inversion
         
     | 
| 
      
 121 
     | 
    
         
            +
             
     | 
| 
      
 122 
     | 
    
         
            +
             
     | 
| 
      
 123 
     | 
    
         
            +
            == Contributing
         
     | 
| 
      
 124 
     | 
    
         
            +
             
     | 
| 
      
 125 
     | 
    
         
            +
            You can check out the current development source
         
     | 
| 
      
 126 
     | 
    
         
            +
            {with Mercurial}[http://repo.deveiate.org/Inversion], or if you prefer Git, via the
         
     | 
| 
      
 127 
     | 
    
         
            +
            project's {Github mirror}[https://github.com/ged/Inversion].
         
     | 
| 
      
 128 
     | 
    
         
            +
             
     | 
| 
      
 129 
     | 
    
         
            +
            You can submit bug reports, suggestions, and read more about future plans at
         
     | 
| 
      
 130 
     | 
    
         
            +
            {the project page}[http://deveiate.org/projects/Inversion].
         
     | 
| 
      
 131 
     | 
    
         
            +
             
     | 
| 
      
 132 
     | 
    
         
            +
            After checking out the source, run:
         
     | 
| 
      
 133 
     | 
    
         
            +
             
     | 
| 
      
 134 
     | 
    
         
            +
            	$ rake newb
         
     | 
| 
      
 135 
     | 
    
         
            +
             
     | 
| 
      
 136 
     | 
    
         
            +
            This task will install any missing dependencies, run the tests/specs,
         
     | 
| 
      
 137 
     | 
    
         
            +
            and generate the API documentation.
         
     | 
| 
      
 138 
     | 
    
         
            +
             
     | 
| 
      
 139 
     | 
    
         
            +
             
     | 
| 
      
 140 
     | 
    
         
            +
            == License
         
     | 
| 
      
 141 
     | 
    
         
            +
             
     | 
| 
      
 142 
     | 
    
         
            +
            Copyright © 2011, Michael Granger and Mahlon E. Smith
         
     | 
| 
      
 143 
     | 
    
         
            +
            All rights reserved.
         
     | 
| 
      
 144 
     | 
    
         
            +
             
     | 
| 
      
 145 
     | 
    
         
            +
            Redistribution and use in source and binary forms, with or without
         
     | 
| 
      
 146 
     | 
    
         
            +
            modification, are permitted provided that the following conditions are met:
         
     | 
| 
      
 147 
     | 
    
         
            +
             
     | 
| 
      
 148 
     | 
    
         
            +
            * Redistributions of source code must retain the above copyright notice,
         
     | 
| 
      
 149 
     | 
    
         
            +
              this list of conditions and the following disclaimer.
         
     | 
| 
      
 150 
     | 
    
         
            +
             
     | 
| 
      
 151 
     | 
    
         
            +
            * Redistributions in binary form must reproduce the above copyright notice,
         
     | 
| 
      
 152 
     | 
    
         
            +
              this list of conditions and the following disclaimer in the documentation
         
     | 
| 
      
 153 
     | 
    
         
            +
              and/or other materials provided with the distribution.
         
     | 
| 
      
 154 
     | 
    
         
            +
             
     | 
| 
      
 155 
     | 
    
         
            +
            * Neither the name of the author/s, nor the names of the project's
         
     | 
| 
      
 156 
     | 
    
         
            +
              contributors may be used to endorse or promote products derived from this
         
     | 
| 
      
 157 
     | 
    
         
            +
              software without specific prior written permission.
         
     | 
| 
      
 158 
     | 
    
         
            +
             
     | 
| 
      
 159 
     | 
    
         
            +
            THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
         
     | 
| 
      
 160 
     | 
    
         
            +
            AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
         
     | 
| 
      
 161 
     | 
    
         
            +
            IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
         
     | 
| 
      
 162 
     | 
    
         
            +
            DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
         
     | 
| 
      
 163 
     | 
    
         
            +
            FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
         
     | 
| 
      
 164 
     | 
    
         
            +
            DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
         
     | 
| 
      
 165 
     | 
    
         
            +
            SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
         
     | 
| 
      
 166 
     | 
    
         
            +
            CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
         
     | 
| 
      
 167 
     | 
    
         
            +
            OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
         
     | 
| 
      
 168 
     | 
    
         
            +
            OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
         
     | 
| 
      
 169 
     | 
    
         
            +
             
     | 
| 
      
 170 
     | 
    
         
            +
             
     | 
| 
      
 171 
     | 
    
         
            +
             
     | 
    
        data/Rakefile
    ADDED
    
    | 
         @@ -0,0 +1,55 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            #!/usr/bin/env rake
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            begin
         
     | 
| 
      
 4 
     | 
    
         
            +
            	require 'hoe'
         
     | 
| 
      
 5 
     | 
    
         
            +
            rescue LoadError
         
     | 
| 
      
 6 
     | 
    
         
            +
            	abort "This Rakefile requires hoe (gem install hoe)"
         
     | 
| 
      
 7 
     | 
    
         
            +
            end
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
            Hoe.plugin :mercurial
         
     | 
| 
      
 10 
     | 
    
         
            +
            Hoe.plugin :signing
         
     | 
| 
      
 11 
     | 
    
         
            +
            Hoe.plugin :manualgen
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
            Hoe.plugins.delete :rubyforge
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
            hoespec = Hoe.spec 'inversion' do
         
     | 
| 
      
 16 
     | 
    
         
            +
            	self.readme_file = 'README.rdoc'
         
     | 
| 
      
 17 
     | 
    
         
            +
            	self.history_file = 'History.md'
         
     | 
| 
      
 18 
     | 
    
         
            +
            	self.extra_rdoc_files = ['README.rdoc']
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
            	self.developer 'Michael Granger', 'ged@FaerieMUD.org'
         
     | 
| 
      
 21 
     | 
    
         
            +
            	self.developer 'Mahlon E. Smith', 'mahlon@martini.nu'
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
            	self.dependency 'ripper',        '~> 1.0',    :development unless defined?( Encoding )
         
     | 
| 
      
 24 
     | 
    
         
            +
            	self.dependency 'rspec',         '~> 2.6.0',  :development
         
     | 
| 
      
 25 
     | 
    
         
            +
            	self.dependency 'tilt',          '~> 1.3.2',  :development
         
     | 
| 
      
 26 
     | 
    
         
            +
            	self.dependency 'sinatra',       '~> 1.2.6',  :development
         
     | 
| 
      
 27 
     | 
    
         
            +
            	self.dependency 'rack-test',     '~> 0.6.0',  :development
         
     | 
| 
      
 28 
     | 
    
         
            +
            	self.dependency 'simplecov',     '~> 0.4.2',  :development
         
     | 
| 
      
 29 
     | 
    
         
            +
            	self.dependency 'hoe-manualgen', '~> 0.2.0',  :development
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
            	# bin/inversion deps
         
     | 
| 
      
 32 
     | 
    
         
            +
            	self.dependency 'trollop',       '~> 0.16.2', :development
         
     | 
| 
      
 33 
     | 
    
         
            +
            	self.dependency 'highline',      '~> 1.6.2',  :development
         
     | 
| 
      
 34 
     | 
    
         
            +
            	self.dependency 'sysexits',      '~> 1.0.2',  :development
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
            	self.spec_extras[:licenses] = ["BSD"]
         
     | 
| 
      
 37 
     | 
    
         
            +
            	self.require_ruby_version( '>=1.9.2' )
         
     | 
| 
      
 38 
     | 
    
         
            +
            	self.hg_sign_tags = true if self.respond_to?( :hg_sign_tags= )
         
     | 
| 
      
 39 
     | 
    
         
            +
            	self.rdoc_locations << "deveiate:/usr/local/www/public/code/#{remote_rdoc_dir}"
         
     | 
| 
      
 40 
     | 
    
         
            +
            end
         
     | 
| 
      
 41 
     | 
    
         
            +
             
     | 
| 
      
 42 
     | 
    
         
            +
            ENV['VERSION'] ||= hoespec.spec.version.to_s
         
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
      
 44 
     | 
    
         
            +
            # Ensure the specs pass before checking in
         
     | 
| 
      
 45 
     | 
    
         
            +
            task 'hg:precheckin' => :spec
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
            # Rebuild the ChangeLog immediately before release (hoe hook)
         
     | 
| 
      
 48 
     | 
    
         
            +
            task :prerelease => 'ChangeLog'
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
            desc "Build a coverage report"
         
     | 
| 
      
 51 
     | 
    
         
            +
            task :coverage do
         
     | 
| 
      
 52 
     | 
    
         
            +
            	ENV["COVERAGE"] = 'yes'
         
     | 
| 
      
 53 
     | 
    
         
            +
            	Rake::Task[:spec].invoke
         
     | 
| 
      
 54 
     | 
    
         
            +
            end
         
     | 
| 
      
 55 
     | 
    
         
            +
             
     | 
    
        data/bin/inversion
    ADDED
    
    | 
         @@ -0,0 +1,276 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            #!/usr/bin/env ruby
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            require 'logger'
         
     | 
| 
      
 4 
     | 
    
         
            +
            require 'inversion'
         
     | 
| 
      
 5 
     | 
    
         
            +
            require 'trollop'
         
     | 
| 
      
 6 
     | 
    
         
            +
            require 'highline'
         
     | 
| 
      
 7 
     | 
    
         
            +
            require 'sysexits'
         
     | 
| 
      
 8 
     | 
    
         
            +
            require 'shellwords'
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
            # Command class for the 'inversion' command-line tool.
         
     | 
| 
      
 11 
     | 
    
         
            +
            class Inversion::Command
         
     | 
| 
      
 12 
     | 
    
         
            +
            	extend Sysexits
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
            	# The list of valid subcommands
         
     | 
| 
      
 15 
     | 
    
         
            +
            	SUBCOMMANDS = %w[api tagtokens tree]
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
            	# Class-instance variable for the HighLine prompt object
         
     | 
| 
      
 18 
     | 
    
         
            +
            	@prompt = nil
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
            	### Run the command
         
     | 
| 
      
 22 
     | 
    
         
            +
            	def self::run( args )
         
     | 
| 
      
 23 
     | 
    
         
            +
            		opts, args = self.parse_options( args )
         
     | 
| 
      
 24 
     | 
    
         
            +
            		subcommand = args.shift
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
            		command = self.new( opts )
         
     | 
| 
      
 27 
     | 
    
         
            +
            		command.run( subcommand, args )
         
     | 
| 
      
 28 
     | 
    
         
            +
            	rescue => err
         
     | 
| 
      
 29 
     | 
    
         
            +
            		$stderr.puts "%p: %s" % [ err.class, err.message ]
         
     | 
| 
      
 30 
     | 
    
         
            +
            		$stderr.puts( err.backtrace.join("\n  ") ) if opts && opts.debug
         
     | 
| 
      
 31 
     | 
    
         
            +
            	end
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
            	### Fetch the HighLine instance for the command, creating it if necessary.
         
     | 
| 
      
 35 
     | 
    
         
            +
            	def self::prompt
         
     | 
| 
      
 36 
     | 
    
         
            +
            		unless @prompt
         
     | 
| 
      
 37 
     | 
    
         
            +
            			@prompt = HighLine.new
         
     | 
| 
      
 38 
     | 
    
         
            +
            			@prompt.page_at = @prompt.output_rows - 5
         
     | 
| 
      
 39 
     | 
    
         
            +
            			@prompt.wrap_at = @prompt.output_cols - 2
         
     | 
| 
      
 40 
     | 
    
         
            +
            		end
         
     | 
| 
      
 41 
     | 
    
         
            +
             
     | 
| 
      
 42 
     | 
    
         
            +
            		@prompt
         
     | 
| 
      
 43 
     | 
    
         
            +
            	end
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
            	### Create an option parser for the command and return it
         
     | 
| 
      
 47 
     | 
    
         
            +
            	def self::create_option_parser
         
     | 
| 
      
 48 
     | 
    
         
            +
            		pr = self.prompt
         
     | 
| 
      
 49 
     | 
    
         
            +
            		progname = pr.color( File.basename($0), :bold, :yellow )
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
            		return Trollop::Parser.new do
         
     | 
| 
      
 52 
     | 
    
         
            +
            			version Inversion.version_string( true )
         
     | 
| 
      
 53 
     | 
    
         
            +
             
     | 
| 
      
 54 
     | 
    
         
            +
            			banner (<<-END_BANNER).gsub(/^\t+/, '')
         
     | 
| 
      
 55 
     | 
    
         
            +
            			#{progname} OPTIONS SUBCOMMAND ARGS
         
     | 
| 
      
 56 
     | 
    
         
            +
            	
         
     | 
| 
      
 57 
     | 
    
         
            +
            			Run the specified SUBCOMMAND with the given ARGS.
         
     | 
| 
      
 58 
     | 
    
         
            +
            			END_BANNER
         
     | 
| 
      
 59 
     | 
    
         
            +
            			text ''
         
     | 
| 
      
 60 
     | 
    
         
            +
             
     | 
| 
      
 61 
     | 
    
         
            +
            			stop_on( *SUBCOMMANDS )
         
     | 
| 
      
 62 
     | 
    
         
            +
            			text pr.color('Subcommands', :bold, :white)
         
     | 
| 
      
 63 
     | 
    
         
            +
            			text pr.list( SUBCOMMANDS, :columns_across )
         
     | 
| 
      
 64 
     | 
    
         
            +
            			text ''
         
     | 
| 
      
 65 
     | 
    
         
            +
             
     | 
| 
      
 66 
     | 
    
         
            +
            			text pr.color('Inversion Config', :bold, :white)
         
     | 
| 
      
 67 
     | 
    
         
            +
            			opt :ignore_unknown_tags, "Ignore unknown tags instead of displaying an error"
         
     | 
| 
      
 68 
     | 
    
         
            +
            			opt :path, "Add one or more directories to the template search path",
         
     | 
| 
      
 69 
     | 
    
         
            +
            				:type => :string, :multi => true
         
     | 
| 
      
 70 
     | 
    
         
            +
            			text ''
         
     | 
| 
      
 71 
     | 
    
         
            +
             
     | 
| 
      
 72 
     | 
    
         
            +
             
     | 
| 
      
 73 
     | 
    
         
            +
            			text pr.color('Other Options', :bold, :white)
         
     | 
| 
      
 74 
     | 
    
         
            +
            			opt :debug, "Enable debugging output"
         
     | 
| 
      
 75 
     | 
    
         
            +
            		end
         
     | 
| 
      
 76 
     | 
    
         
            +
            	end
         
     | 
| 
      
 77 
     | 
    
         
            +
             
     | 
| 
      
 78 
     | 
    
         
            +
             
     | 
| 
      
 79 
     | 
    
         
            +
            	### Parse the given command line +args+, returning a populated options struct
         
     | 
| 
      
 80 
     | 
    
         
            +
            	### and any remaining arguments.
         
     | 
| 
      
 81 
     | 
    
         
            +
            	def self::parse_options( args )
         
     | 
| 
      
 82 
     | 
    
         
            +
            		oparser = self.create_option_parser
         
     | 
| 
      
 83 
     | 
    
         
            +
            		opts = oparser.parse( args )
         
     | 
| 
      
 84 
     | 
    
         
            +
             
     | 
| 
      
 85 
     | 
    
         
            +
            		if oparser.leftovers.empty?
         
     | 
| 
      
 86 
     | 
    
         
            +
            			$stderr.puts "No subcommand given.\nUsage: "
         
     | 
| 
      
 87 
     | 
    
         
            +
            			oparser.educate( $stderr )
         
     | 
| 
      
 88 
     | 
    
         
            +
            			exit :usage
         
     | 
| 
      
 89 
     | 
    
         
            +
            		end
         
     | 
| 
      
 90 
     | 
    
         
            +
            		args.replace( oparser.leftovers )
         
     | 
| 
      
 91 
     | 
    
         
            +
             
     | 
| 
      
 92 
     | 
    
         
            +
            		return opts, args
         
     | 
| 
      
 93 
     | 
    
         
            +
            	rescue Trollop::HelpNeeded
         
     | 
| 
      
 94 
     | 
    
         
            +
            		oparser.educate( $stderr )
         
     | 
| 
      
 95 
     | 
    
         
            +
            		exit :ok
         
     | 
| 
      
 96 
     | 
    
         
            +
            	rescue Trollop::VersionNeeded
         
     | 
| 
      
 97 
     | 
    
         
            +
            		$stderr.puts( oparser.version )
         
     | 
| 
      
 98 
     | 
    
         
            +
            		exit :ok
         
     | 
| 
      
 99 
     | 
    
         
            +
            	end
         
     | 
| 
      
 100 
     | 
    
         
            +
             
     | 
| 
      
 101 
     | 
    
         
            +
             
     | 
| 
      
 102 
     | 
    
         
            +
            	### Create a new instance of the command that will use the specified +opts+
         
     | 
| 
      
 103 
     | 
    
         
            +
            	### to parse and dump info about the given +templates+.
         
     | 
| 
      
 104 
     | 
    
         
            +
            	def initialize( opts )
         
     | 
| 
      
 105 
     | 
    
         
            +
            		@opts      = opts
         
     | 
| 
      
 106 
     | 
    
         
            +
            		@prompt    = self.class.prompt
         
     | 
| 
      
 107 
     | 
    
         
            +
             
     | 
| 
      
 108 
     | 
    
         
            +
            		# Configure Inversion's strictness and logging
         
     | 
| 
      
 109 
     | 
    
         
            +
            		Inversion.log.level = opts.debug ? Logger::DEBUG : Logger::ERROR
         
     | 
| 
      
 110 
     | 
    
         
            +
            		Inversion.log.formatter = Inversion::ColorLogFormatter.new( Inversion.log )
         
     | 
| 
      
 111 
     | 
    
         
            +
            		Inversion::Template.configure(
         
     | 
| 
      
 112 
     | 
    
         
            +
            			:ignore_unknown_tags => opts.ignore_unknown_tags,
         
     | 
| 
      
 113 
     | 
    
         
            +
            			:template_paths      => opts.path,
         
     | 
| 
      
 114 
     | 
    
         
            +
            		)
         
     | 
| 
      
 115 
     | 
    
         
            +
            	end
         
     | 
| 
      
 116 
     | 
    
         
            +
             
     | 
| 
      
 117 
     | 
    
         
            +
             
     | 
| 
      
 118 
     | 
    
         
            +
            	######
         
     | 
| 
      
 119 
     | 
    
         
            +
            	public
         
     | 
| 
      
 120 
     | 
    
         
            +
            	######
         
     | 
| 
      
 121 
     | 
    
         
            +
             
     | 
| 
      
 122 
     | 
    
         
            +
            	# The command-line options
         
     | 
| 
      
 123 
     | 
    
         
            +
            	attr_reader :opts
         
     | 
| 
      
 124 
     | 
    
         
            +
             
     | 
| 
      
 125 
     | 
    
         
            +
            	# The command's prompt object (HighLine)
         
     | 
| 
      
 126 
     | 
    
         
            +
            	attr_reader :prompt
         
     | 
| 
      
 127 
     | 
    
         
            +
             
     | 
| 
      
 128 
     | 
    
         
            +
             
     | 
| 
      
 129 
     | 
    
         
            +
            	### Run the given +subcommand+ with the specified +args+.
         
     | 
| 
      
 130 
     | 
    
         
            +
            	def run( subcommand, args )
         
     | 
| 
      
 131 
     | 
    
         
            +
            		case subcommand.to_sym
         
     | 
| 
      
 132 
     | 
    
         
            +
            		when :tree
         
     | 
| 
      
 133 
     | 
    
         
            +
            			self.dump_node_trees( args )
         
     | 
| 
      
 134 
     | 
    
         
            +
            		when :api
         
     | 
| 
      
 135 
     | 
    
         
            +
            			self.describe_templates( args )
         
     | 
| 
      
 136 
     | 
    
         
            +
            		when :tagtokens
         
     | 
| 
      
 137 
     | 
    
         
            +
            			self.dump_tokens( args )
         
     | 
| 
      
 138 
     | 
    
         
            +
            		else
         
     | 
| 
      
 139 
     | 
    
         
            +
            			self.output_error( "No such command #{subcommand.dump}" )
         
     | 
| 
      
 140 
     | 
    
         
            +
            		end
         
     | 
| 
      
 141 
     | 
    
         
            +
            	end
         
     | 
| 
      
 142 
     | 
    
         
            +
             
     | 
| 
      
 143 
     | 
    
         
            +
             
     | 
| 
      
 144 
     | 
    
         
            +
            	### Load the Inversion::Template from the specified +tmplpath+ and return it. If there
         
     | 
| 
      
 145 
     | 
    
         
            +
            	### is an error loading the template, output the error and return +nil+.
         
     | 
| 
      
 146 
     | 
    
         
            +
            	def load_template( tmplpath )
         
     | 
| 
      
 147 
     | 
    
         
            +
            		template = Inversion::Template.load( tmplpath )
         
     | 
| 
      
 148 
     | 
    
         
            +
            		return template
         
     | 
| 
      
 149 
     | 
    
         
            +
            	rescue Errno => err
         
     | 
| 
      
 150 
     | 
    
         
            +
            		self.prompt.say "Failed to load %s: %s" % [ tmplpath, err.message ]
         
     | 
| 
      
 151 
     | 
    
         
            +
            	rescue Inversion::ParseError => err
         
     | 
| 
      
 152 
     | 
    
         
            +
            		self.prompt.say "%s: Invalid template: %p: %s" %
         
     | 
| 
      
 153 
     | 
    
         
            +
            			[ tmplpath, err.class, err.message ]
         
     | 
| 
      
 154 
     | 
    
         
            +
            		self.prompt.say( err.backtrace.join("\n  ") ) if self.opts.debug
         
     | 
| 
      
 155 
     | 
    
         
            +
            	end
         
     | 
| 
      
 156 
     | 
    
         
            +
             
     | 
| 
      
 157 
     | 
    
         
            +
             
     | 
| 
      
 158 
     | 
    
         
            +
            	### Dump the node tree of the given +templates+.
         
     | 
| 
      
 159 
     | 
    
         
            +
            	def dump_node_trees( templates )
         
     | 
| 
      
 160 
     | 
    
         
            +
            		templates.each do |path|
         
     | 
| 
      
 161 
     | 
    
         
            +
            			template = self.load_template( path )
         
     | 
| 
      
 162 
     | 
    
         
            +
            			self.output_blank_line
         
     | 
| 
      
 163 
     | 
    
         
            +
            			self.output_template_header( template )
         
     | 
| 
      
 164 
     | 
    
         
            +
            			self.output_template_nodes( template.node_tree )
         
     | 
| 
      
 165 
     | 
    
         
            +
            		end
         
     | 
| 
      
 166 
     | 
    
         
            +
            	end
         
     | 
| 
      
 167 
     | 
    
         
            +
             
     | 
| 
      
 168 
     | 
    
         
            +
             
     | 
| 
      
 169 
     | 
    
         
            +
            	### Output the given +tree+ of nodes at the specified +indent+ level.
         
     | 
| 
      
 170 
     | 
    
         
            +
            	def output_template_nodes( tree, indent=0 )
         
     | 
| 
      
 171 
     | 
    
         
            +
            		indenttxt = ' ' * indent
         
     | 
| 
      
 172 
     | 
    
         
            +
            		tree.each do |node|
         
     | 
| 
      
 173 
     | 
    
         
            +
            			self.prompt.say( indenttxt + node.as_comment_body )
         
     | 
| 
      
 174 
     | 
    
         
            +
            			self.output_template_nodes( node.subnodes, indent+4 ) if node.is_container?
         
     | 
| 
      
 175 
     | 
    
         
            +
            		end
         
     | 
| 
      
 176 
     | 
    
         
            +
            	end
         
     | 
| 
      
 177 
     | 
    
         
            +
             
     | 
| 
      
 178 
     | 
    
         
            +
             
     | 
| 
      
 179 
     | 
    
         
            +
            	### Output a description of the templates.
         
     | 
| 
      
 180 
     | 
    
         
            +
            	def describe_templates( templates )
         
     | 
| 
      
 181 
     | 
    
         
            +
            		templates.each do |path|
         
     | 
| 
      
 182 
     | 
    
         
            +
            			template = self.load_template( path )
         
     | 
| 
      
 183 
     | 
    
         
            +
            			self.output_blank_line
         
     | 
| 
      
 184 
     | 
    
         
            +
            			self.output_template_header( template )
         
     | 
| 
      
 185 
     | 
    
         
            +
            			self.describe_template_api( template )
         
     | 
| 
      
 186 
     | 
    
         
            +
            			self.describe_publications( template )
         
     | 
| 
      
 187 
     | 
    
         
            +
            			self.describe_subscriptions( template )
         
     | 
| 
      
 188 
     | 
    
         
            +
            		end
         
     | 
| 
      
 189 
     | 
    
         
            +
            	end
         
     | 
| 
      
 190 
     | 
    
         
            +
             
     | 
| 
      
 191 
     | 
    
         
            +
             
     | 
| 
      
 192 
     | 
    
         
            +
            	### Output a header between each template.
         
     | 
| 
      
 193 
     | 
    
         
            +
            	def output_template_header( template )
         
     | 
| 
      
 194 
     | 
    
         
            +
            		header_info = "%s (%0.2fK, %s)" %
         
     | 
| 
      
 195 
     | 
    
         
            +
            			[ template.source_file, template.source.bytesize/1024.0, template.source.encoding ]
         
     | 
| 
      
 196 
     | 
    
         
            +
            		header_line = "-- %s" % [ header_info ]
         
     | 
| 
      
 197 
     | 
    
         
            +
            		self.prompt.say( self.prompt.color(header_line, :bold, :white) )
         
     | 
| 
      
 198 
     | 
    
         
            +
            	end
         
     | 
| 
      
 199 
     | 
    
         
            +
             
     | 
| 
      
 200 
     | 
    
         
            +
             
     | 
| 
      
 201 
     | 
    
         
            +
            	### Output a description of the +template+'s attributes, subscriptions, etc.
         
     | 
| 
      
 202 
     | 
    
         
            +
            	def describe_template_api( template )
         
     | 
| 
      
 203 
     | 
    
         
            +
            		attrs = template.attributes.keys.map( &:to_s )
         
     | 
| 
      
 204 
     | 
    
         
            +
            		return if attrs.empty?
         
     | 
| 
      
 205 
     | 
    
         
            +
             
     | 
| 
      
 206 
     | 
    
         
            +
            		self.output_subheader "%d Attribute/s" % [ attrs.length ]
         
     | 
| 
      
 207 
     | 
    
         
            +
            		self.output_list( attrs.sort )
         
     | 
| 
      
 208 
     | 
    
         
            +
            		self.output_blank_line
         
     | 
| 
      
 209 
     | 
    
         
            +
            	end
         
     | 
| 
      
 210 
     | 
    
         
            +
             
     | 
| 
      
 211 
     | 
    
         
            +
             
     | 
| 
      
 212 
     | 
    
         
            +
            	### Output a list of sections the template publishes.
         
     | 
| 
      
 213 
     | 
    
         
            +
            	def describe_publications( template )
         
     | 
| 
      
 214 
     | 
    
         
            +
            		ptags = template.node_tree.find_all {|node| node.is_a?(Inversion::Template::PublishTag) }
         
     | 
| 
      
 215 
     | 
    
         
            +
            		return if ptags.empty?
         
     | 
| 
      
 216 
     | 
    
         
            +
             
     | 
| 
      
 217 
     | 
    
         
            +
            		pubnames = ptags.map( &:key ).map( &:to_s ).uniq.sort
         
     | 
| 
      
 218 
     | 
    
         
            +
            		self.output_subheader "%d Publication/s" % [ pubnames.length ]
         
     | 
| 
      
 219 
     | 
    
         
            +
            		self.output_list( pubnames )
         
     | 
| 
      
 220 
     | 
    
         
            +
            		self.output_blank_line
         
     | 
| 
      
 221 
     | 
    
         
            +
            	end
         
     | 
| 
      
 222 
     | 
    
         
            +
             
     | 
| 
      
 223 
     | 
    
         
            +
             
     | 
| 
      
 224 
     | 
    
         
            +
            	### Output a list of sections the template subscribes to.
         
     | 
| 
      
 225 
     | 
    
         
            +
            	def describe_subscriptions( template )
         
     | 
| 
      
 226 
     | 
    
         
            +
            		stags = template.node_tree.find_all {|node| node.is_a?(Inversion::Template::SubscribeTag) }
         
     | 
| 
      
 227 
     | 
    
         
            +
            		return if stags.empty?
         
     | 
| 
      
 228 
     | 
    
         
            +
             
     | 
| 
      
 229 
     | 
    
         
            +
            		subnames = stags.map( &:key ).map( &:to_s ).uniq.sort
         
     | 
| 
      
 230 
     | 
    
         
            +
            		self.output_subheader "%d Subscription/s" % [ subnames.length ]
         
     | 
| 
      
 231 
     | 
    
         
            +
            		self.output_list( subnames )
         
     | 
| 
      
 232 
     | 
    
         
            +
            		self.output_blank_line
         
     | 
| 
      
 233 
     | 
    
         
            +
            	end
         
     | 
| 
      
 234 
     | 
    
         
            +
             
     | 
| 
      
 235 
     | 
    
         
            +
             
     | 
| 
      
 236 
     | 
    
         
            +
            	### Attempt to parse the given +code+ and dump its tokens as a tagpattern.
         
     | 
| 
      
 237 
     | 
    
         
            +
            	def dump_tokens( args )
         
     | 
| 
      
 238 
     | 
    
         
            +
            		code = args.join(' ')
         
     | 
| 
      
 239 
     | 
    
         
            +
             
     | 
| 
      
 240 
     | 
    
         
            +
            		require 'ripper'
         
     | 
| 
      
 241 
     | 
    
         
            +
            		tokens = Ripper.lex( code ).collect do |(pos, tok, text)|
         
     | 
| 
      
 242 
     | 
    
         
            +
            			"%s<%p>" % [ tok.to_s.sub(/^on_/,''), text ]
         
     | 
| 
      
 243 
     | 
    
         
            +
            		end.join(' ')
         
     | 
| 
      
 244 
     | 
    
         
            +
             
     | 
| 
      
 245 
     | 
    
         
            +
            		self.prompt.say( tokens )
         
     | 
| 
      
 246 
     | 
    
         
            +
            	end
         
     | 
| 
      
 247 
     | 
    
         
            +
             
     | 
| 
      
 248 
     | 
    
         
            +
             
     | 
| 
      
 249 
     | 
    
         
            +
            	### Display a columnar list.
         
     | 
| 
      
 250 
     | 
    
         
            +
            	def output_list( columns )
         
     | 
| 
      
 251 
     | 
    
         
            +
            		self.prompt.say( self.prompt.list(columns, :columns_down) )
         
     | 
| 
      
 252 
     | 
    
         
            +
            	end
         
     | 
| 
      
 253 
     | 
    
         
            +
             
     | 
| 
      
 254 
     | 
    
         
            +
             
     | 
| 
      
 255 
     | 
    
         
            +
            	### Display an error message.
         
     | 
| 
      
 256 
     | 
    
         
            +
            	def output_error( message )
         
     | 
| 
      
 257 
     | 
    
         
            +
            		self.prompt.say( self.prompt.color(message, :red) )
         
     | 
| 
      
 258 
     | 
    
         
            +
            	end
         
     | 
| 
      
 259 
     | 
    
         
            +
             
     | 
| 
      
 260 
     | 
    
         
            +
             
     | 
| 
      
 261 
     | 
    
         
            +
            	### Output a subheader with the given +caption+.
         
     | 
| 
      
 262 
     | 
    
         
            +
            	def output_subheader( caption )
         
     | 
| 
      
 263 
     | 
    
         
            +
            		self.prompt.say( self.prompt.color(caption, :cyan) )
         
     | 
| 
      
 264 
     | 
    
         
            +
            	end
         
     | 
| 
      
 265 
     | 
    
         
            +
             
     | 
| 
      
 266 
     | 
    
         
            +
             
     | 
| 
      
 267 
     | 
    
         
            +
            	### Output a blank line
         
     | 
| 
      
 268 
     | 
    
         
            +
            	def output_blank_line
         
     | 
| 
      
 269 
     | 
    
         
            +
            		self.prompt.say( "\n" )
         
     | 
| 
      
 270 
     | 
    
         
            +
            	end
         
     | 
| 
      
 271 
     | 
    
         
            +
             
     | 
| 
      
 272 
     | 
    
         
            +
            end # class Inversion::Command
         
     | 
| 
      
 273 
     | 
    
         
            +
             
     | 
| 
      
 274 
     | 
    
         
            +
            Inversion::Command.run( ARGV )
         
     | 
| 
      
 275 
     | 
    
         
            +
             
     | 
| 
      
 276 
     | 
    
         
            +
             
     |