brief 1.0.0 → 1.1.0
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.
- checksums.yaml +4 -4
- data/.gitignore +2 -0
- data/README.md +66 -127
- data/TUTORIAL.md +146 -0
- data/examples/blog/brief.rb +2 -28
- data/lib/brief.rb +8 -0
- data/lib/brief/document_mapper.rb +1 -0
- data/lib/brief/model.rb +29 -28
- data/lib/brief/model/definition.rb +22 -9
- data/lib/brief/model/persistence.rb +7 -0
- data/lib/brief/util.rb +36 -0
- data/lib/brief/version.rb +1 -1
- data/spec/fixtures/example/brief.rb +5 -5
- data/spec/fixtures/example/models/epic.rb +7 -1
- data/spec/lib/brief/model_spec.rb +21 -0
- data/spec/lib/brief/persistence_spec.rb +9 -0
- metadata +7 -2
- data/lib/brief/cli/publish.rb +0 -0
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA1:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 4ea25b279da5166d726a9463be10836ab9b6d7bb
         | 
| 4 | 
            +
              data.tar.gz: e52d0270a01c924196c8ab59250df0973320589d
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 250b23f611f467ec9731114557f84d8bf24e498642849eab59dcb79f7a7c1790ea33b8f734a3017f515ad025caf5353625b0ec972c7e016eb7682eafe9aa063a
         | 
| 7 | 
            +
              data.tar.gz: 88a4250edb54523fdb51f18700a149831a5835d031cf67fbc49c142bb6d3abeccec9eff48c32df99f9ded979330c9223b7f7934819b87e4f79f33a67292b2e3e
         | 
    
        data/.gitignore
    ADDED
    
    
    
        data/README.md
    CHANGED
    
    | @@ -2,171 +2,110 @@ | |
| 2 2 |  | 
| 3 3 | 
             
            An ActiveRecord style layer on top of a folder of markdown files.
         | 
| 4 4 |  | 
| 5 | 
            -
             | 
| 5 | 
            +
            Treat your markdown documents as active models, run actions on them,
         | 
| 6 | 
            +
            convert them into HTML, extract fragments of HTML, combine it all in
         | 
| 7 | 
            +
            whatever interesting way you can think of.  
         | 
| 6 8 |  | 
| 7 | 
            -
             | 
| 8 | 
            -
             | 
| 9 | 
            -
            which contains folders with different document types.
         | 
| 9 | 
            +
            The end result is a really neat way of being able to use the words that you write
         | 
| 10 | 
            +
            to power all sorts of applications. 
         | 
| 10 11 |  | 
| 11 | 
            -
             | 
| 12 | 
            -
            which can be specified in a YAML frontmatter preamble at the very top of
         | 
| 13 | 
            -
            each document.  
         | 
| 12 | 
            +
            **No more writing dead documents!**
         | 
| 14 13 |  | 
| 15 | 
            -
             | 
| 16 | 
            -
            attributes as CSS selectors.  For example, the very first h1 heading
         | 
| 17 | 
            -
            could be the title for your document, and the corresponding model for
         | 
| 18 | 
            -
            that document would have a `title` method which returned its value.
         | 
| 14 | 
            +
            ### Documents as Models
         | 
| 19 15 |  | 
| 20 | 
            -
             | 
| 21 | 
            -
             | 
| 22 | 
            -
             | 
| 23 | 
            -
             | 
| 24 | 
            -
            **Think of it as an ActiveRecord like layer on top of a folder of
         | 
| 25 | 
            -
            Markdown files**.  Brief turns static text into a 'living' data object.
         | 
| 26 | 
            -
             | 
| 27 | 
            -
            ## Getting started 
         | 
| 28 | 
            -
             | 
| 29 | 
            -
            ```bash
         | 
| 30 | 
            -
            gem install brief
         | 
| 31 | 
            -
            mkdir blog
         | 
| 32 | 
            -
            cd blog 
         | 
| 33 | 
            -
            brief init
         | 
| 34 | 
            -
            ```
         | 
| 35 | 
            -
             | 
| 36 | 
            -
            This will create a new folder for your briefcase, along with the
         | 
| 37 | 
            -
            following config file and structure.
         | 
| 38 | 
            -
             | 
| 39 | 
            -
            ```
         | 
| 40 | 
            -
            - docs/
         | 
| 41 | 
            -
              - an-introduction-to-brief.html.md
         | 
| 42 | 
            -
            - models/
         | 
| 43 | 
            -
            - brief.rb
         | 
| 44 | 
            -
            ```
         | 
| 45 | 
            -
             | 
| 46 | 
            -
            The config file will look like:
         | 
| 16 | 
            +
            Brief lets you treat an individual markdown file as if it were a model,
         | 
| 17 | 
            +
            complete with validations, callbacks, and methods you can run. You can
         | 
| 18 | 
            +
            define a `Post` model for all of the files in a 'posts' folder and
         | 
| 19 | 
            +
            define actions like 'publish' on them. 
         | 
| 47 20 |  | 
| 48 21 | 
             
            ```ruby
         | 
| 49 | 
            -
             | 
| 50 | 
            -
            # configuration options for this briefcase
         | 
| 51 | 
            -
            config do
         | 
| 52 | 
            -
              set(:models_path => Pathname(__FILE__).parent.join("models"))
         | 
| 53 | 
            -
            end
         | 
| 54 | 
            -
             | 
| 55 | 
            -
            # define a Post model
         | 
| 56 | 
            -
            define("Post") do
         | 
| 57 | 
            -
             | 
| 58 | 
            -
              # the post model will have YAML frontmatter 
         | 
| 59 | 
            -
              # with values for 'status' and 'date'
         | 
| 22 | 
            +
            define "Post" do
         | 
| 60 23 | 
             
              meta do
         | 
| 61 24 | 
             
                status
         | 
| 62 | 
            -
                 | 
| 25 | 
            +
                tags Array
         | 
| 63 26 | 
             
              end
         | 
| 64 | 
            -
             | 
| 65 | 
            -
              # the post model will have a 'title' method which returns the text
         | 
| 66 | 
            -
              # from the first h1 heading
         | 
| 27 | 
            +
             | 
| 67 28 | 
             
              content do
         | 
| 68 | 
            -
                title "h1"
         | 
| 29 | 
            +
                has_one :title, "h1"
         | 
| 69 30 | 
             
                has_many :subheadings, "h2"
         | 
| 70 31 | 
             
              end
         | 
| 71 32 |  | 
| 72 | 
            -
               | 
| 73 | 
            -
                def publish | 
| 74 | 
            -
             | 
| 33 | 
            +
              actions do
         | 
| 34 | 
            +
                def publish
         | 
| 35 | 
            +
                  update_attributes(:status => "published")
         | 
| 75 36 | 
             
                end
         | 
| 76 37 | 
             
              end
         | 
| 77 | 
            -
              
         | 
| 78 | 
            -
              # Whenever we call post.save() and the status attribute changes
         | 
| 79 | 
            -
              # from draft to published, do something with the model
         | 
| 80 | 
            -
              on_status_change(:from => "draft", :to => "published") do |model|
         | 
| 81 | 
            -
                # Do Something
         | 
| 82 | 
            -
                # mail_service.send_html_email_campaign(model.to_html)
         | 
| 83 | 
            -
              end
         | 
| 84 38 | 
             
            end
         | 
| 39 | 
            +
            ```
         | 
| 85 40 |  | 
| 86 | 
            -
            # this creates a custom command in the brief CLI tool
         | 
| 87 | 
            -
            #
         | 
| 88 | 
            -
            # so when you run:
         | 
| 89 | 
            -
            # 
         | 
| 90 | 
            -
            #   brief publish posts /path/to/*.html.md.
         | 
| 91 | 
            -
            #
         | 
| 92 | 
            -
            # the brief CLI will find models for the post files you reference,
         | 
| 93 | 
            -
            # and call whatever methods you want.
         | 
| 94 41 |  | 
| 95 | 
            -
             | 
| 42 | 
            +
            ### Model attributes derived from YAML frontmatter 
         | 
| 96 43 |  | 
| 97 | 
            -
             | 
| 44 | 
            +
            Models can get their attributes from headers on the document, aka YAML frontmatter.
         | 
| 98 45 |  | 
| 99 | 
            -
             | 
| 100 | 
            -
             | 
| 101 | 
            -
             | 
| 102 | 
            -
             | 
| 46 | 
            +
            ```markdown
         | 
| 47 | 
            +
            ---
         | 
| 48 | 
            +
            status: draft
         | 
| 49 | 
            +
            tags: 
         | 
| 50 | 
            +
              - demo
         | 
| 51 | 
            +
              - sample
         | 
| 52 | 
            +
            ---
         | 
| 53 | 
            +
             | 
| 54 | 
            +
            # Title
         | 
| 55 | 
            +
             | 
| 56 | 
            +
            ## Section One
         | 
| 57 | 
            +
            ## Section Two
         | 
| 103 58 | 
             
            ```
         | 
| 104 59 |  | 
| 105 | 
            -
             | 
| 60 | 
            +
            which will let you use it like such:
         | 
| 61 | 
            +
             | 
| 62 | 
            +
            ```ruby
         | 
| 63 | 
            +
            post = Brief::Document.new(/path/to/doc.html.md)
         | 
| 64 | 
            +
             | 
| 65 | 
            +
            post.status #=> "draft"
         | 
| 66 | 
            +
            post.title #=> "Title"
         | 
| 67 | 
            +
            post.tags #=> ['demo','sample']
         | 
| 68 | 
            +
            ```
         | 
| 106 69 |  | 
| 107 | 
            -
             | 
| 108 | 
            -
            software.  A Blueprint is a collection of related documents that are
         | 
| 109 | 
            -
            used in the software architecture and design process, as well as in the
         | 
| 110 | 
            -
            day to day writing that takes place while building the software itself.
         | 
| 70 | 
            +
            #### Model attributes derived from the document structure
         | 
| 111 71 |  | 
| 112 | 
            -
             | 
| 72 | 
            +
            Models can also get their attributes from the structure itself.
         | 
| 113 73 |  | 
| 114 | 
            -
             | 
| 115 | 
            -
             | 
| 116 | 
            -
             | 
| 117 | 
            -
             | 
| 118 | 
            -
            - user stories
         | 
| 119 | 
            -
            - integration tests
         | 
| 120 | 
            -
            - release notes
         | 
| 121 | 
            -
            - wireframe annotations
         | 
| 74 | 
            +
            ```ruby
         | 
| 75 | 
            +
            post.title #=> "Title"
         | 
| 76 | 
            +
            post.subheadings #=> ["Section One", "Section Two"]
         | 
| 77 | 
            +
            ```
         | 
| 122 78 |  | 
| 123 | 
            -
             | 
| 124 | 
            -
            projects we are working on, and by treating our writing as a structured
         | 
| 125 | 
            -
            exercise we are able to do a lot more things with it than just read it.
         | 
| 79 | 
            +
            ### Querying Documents
         | 
| 126 80 |  | 
| 127 | 
            -
             | 
| 81 | 
            +
            Given a big folder of markdown files with attributes, we can query them:
         | 
| 128 82 |  | 
| 129 83 | 
             
            ```
         | 
| 130 | 
            -
             | 
| 84 | 
            +
            posts = briefcase.posts.where(:status => "published")
         | 
| 85 | 
            +
            posts.map(&:title) #=> ['Title']
         | 
| 131 86 | 
             
            ```
         | 
| 132 87 |  | 
| 133 | 
            -
             | 
| 88 | 
            +
            This functionality is based on https://github.com/ralph/document_mapper,
         | 
| 89 | 
            +
            and similar to middleman.
         | 
| 134 90 |  | 
| 135 | 
            -
             | 
| 136 | 
            -
            # brief.rb
         | 
| 91 | 
            +
            ### Document Actions
         | 
| 137 92 |  | 
| 138 | 
            -
             | 
| 139 | 
            -
              meta do
         | 
| 140 | 
            -
                status
         | 
| 141 | 
            -
              end
         | 
| 93 | 
            +
            By defining actions on documents like so:
         | 
| 142 94 |  | 
| 143 | 
            -
             | 
| 144 | 
            -
                title "h1"
         | 
| 145 | 
            -
                paragraph "p:first-child"
         | 
| 146 | 
            -
                persona "p:first-child strong:1st-child"
         | 
| 147 | 
            -
                behavior "p:first-child strong:2nd-child"
         | 
| 148 | 
            -
                goal "p:first-child strong:3rd-child"
         | 
| 149 | 
            -
              end
         | 
| 95 | 
            +
            ```ruby
         | 
| 150 96 |  | 
| 151 | 
            -
             | 
| 152 | 
            -
             | 
| 153 | 
            -
             | 
| 154 | 
            -
                   | 
| 97 | 
            +
            define "Post" do
         | 
| 98 | 
            +
              actions do
         | 
| 99 | 
            +
                def publish
         | 
| 100 | 
            +
                  # DO Something
         | 
| 155 101 | 
             
                end
         | 
| 156 102 | 
             
              end
         | 
| 157 103 | 
             
            end
         | 
| 104 | 
            +
            ```
         | 
| 158 105 |  | 
| 159 | 
            -
             | 
| 160 | 
            -
             | 
| 106 | 
            +
            you can either call that method as you normally would, or you can run 
         | 
| 107 | 
            +
            that action from the command line:
         | 
| 161 108 |  | 
| 162 | 
            -
             | 
| 163 | 
            -
             | 
| 164 | 
            -
                  user_story.status = "published"
         | 
| 165 | 
            -
                  user_story.save
         | 
| 166 | 
            -
                end
         | 
| 167 | 
            -
              end
         | 
| 168 | 
            -
            end
         | 
| 109 | 
            +
            ```bash
         | 
| 110 | 
            +
            brief publish posts ./posts/*.html.md
         | 
| 169 111 | 
             
            ```
         | 
| 170 | 
            -
             | 
| 171 | 
            -
            As you can see, Brief can be a way to make your Markdown writing efforts
         | 
| 172 | 
            -
            much more productive. 
         | 
    
        data/TUTORIAL.md
    ADDED
    
    | @@ -0,0 +1,146 @@ | |
| 1 | 
            +
            ## Tutorial
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            ```bash
         | 
| 4 | 
            +
            gem install brief
         | 
| 5 | 
            +
            mkdir blog
         | 
| 6 | 
            +
            cd blog 
         | 
| 7 | 
            +
            brief init
         | 
| 8 | 
            +
            ```
         | 
| 9 | 
            +
             | 
| 10 | 
            +
            This will create a new folder for your briefcase, along with the
         | 
| 11 | 
            +
            following config file and structure.
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            ```
         | 
| 14 | 
            +
            - docs/
         | 
| 15 | 
            +
              - an-introduction-to-brief.html.md
         | 
| 16 | 
            +
            - models/
         | 
| 17 | 
            +
            - brief.rb
         | 
| 18 | 
            +
            ```
         | 
| 19 | 
            +
             | 
| 20 | 
            +
            The config file will look like:
         | 
| 21 | 
            +
             | 
| 22 | 
            +
            ```ruby
         | 
| 23 | 
            +
             | 
| 24 | 
            +
            # configuration options for this briefcase
         | 
| 25 | 
            +
            config do
         | 
| 26 | 
            +
              set(:models_path => Pathname(__FILE__).parent.join("models"))
         | 
| 27 | 
            +
            end
         | 
| 28 | 
            +
             | 
| 29 | 
            +
            # define a Post model
         | 
| 30 | 
            +
            define("Post") do
         | 
| 31 | 
            +
             | 
| 32 | 
            +
              # the post model will have YAML frontmatter 
         | 
| 33 | 
            +
              # with values for 'status' and 'date'
         | 
| 34 | 
            +
              meta do
         | 
| 35 | 
            +
                status
         | 
| 36 | 
            +
                date DateTime, :default => lambda {|post, attr| post.document.created_at }
         | 
| 37 | 
            +
              end
         | 
| 38 | 
            +
              
         | 
| 39 | 
            +
              # the post model will have a 'title' method which returns the text
         | 
| 40 | 
            +
              # from the first h1 heading
         | 
| 41 | 
            +
              content do
         | 
| 42 | 
            +
                title "h1"
         | 
| 43 | 
            +
                has_many :subheadings, "h2"
         | 
| 44 | 
            +
              end
         | 
| 45 | 
            +
             | 
| 46 | 
            +
              helpers do
         | 
| 47 | 
            +
                def publish(options={})
         | 
| 48 | 
            +
             | 
| 49 | 
            +
                end
         | 
| 50 | 
            +
              end
         | 
| 51 | 
            +
              
         | 
| 52 | 
            +
              # Whenever we call post.save() and the status attribute changes
         | 
| 53 | 
            +
              # from draft to published, do something with the model
         | 
| 54 | 
            +
              on_status_change(:from => "draft", :to => "published") do |model|
         | 
| 55 | 
            +
                # Do Something
         | 
| 56 | 
            +
                # mail_service.send_html_email_campaign(model.to_html)
         | 
| 57 | 
            +
              end
         | 
| 58 | 
            +
            end
         | 
| 59 | 
            +
             | 
| 60 | 
            +
            # this creates a custom command in the brief CLI tool
         | 
| 61 | 
            +
            #
         | 
| 62 | 
            +
            # so when you run:
         | 
| 63 | 
            +
            # 
         | 
| 64 | 
            +
            #   brief publish posts /path/to/*.html.md.
         | 
| 65 | 
            +
            #
         | 
| 66 | 
            +
            # the brief CLI will find models for the post files you reference,
         | 
| 67 | 
            +
            # and call whatever methods you want.
         | 
| 68 | 
            +
             | 
| 69 | 
            +
            action "publish posts" do |briefcase, models, options|
         | 
| 70 | 
            +
             | 
| 71 | 
            +
              say "== Publishing #{ models.length } posts"
         | 
| 72 | 
            +
             | 
| 73 | 
            +
              Array(models).each do |post|
         | 
| 74 | 
            +
                post.publish()
         | 
| 75 | 
            +
              end
         | 
| 76 | 
            +
            end
         | 
| 77 | 
            +
            ```
         | 
| 78 | 
            +
             | 
| 79 | 
            +
            ### Real World Application
         | 
| 80 | 
            +
             | 
| 81 | 
            +
            My company Architects.io, Inc. uses brief to power our Blueprint
         | 
| 82 | 
            +
            software.  A Blueprint is a collection of related documents that are
         | 
| 83 | 
            +
            used in the software architecture and design process, as well as in the
         | 
| 84 | 
            +
            day to day writing that takes place while building the software itself.
         | 
| 85 | 
            +
             | 
| 86 | 
            +
            This includes things like:
         | 
| 87 | 
            +
             | 
| 88 | 
            +
            - daily standups
         | 
| 89 | 
            +
            - bug reports
         | 
| 90 | 
            +
            - code reviews
         | 
| 91 | 
            +
            - feature epics
         | 
| 92 | 
            +
            - user stories
         | 
| 93 | 
            +
            - integration tests
         | 
| 94 | 
            +
            - release notes
         | 
| 95 | 
            +
            - wireframe annotations
         | 
| 96 | 
            +
             | 
| 97 | 
            +
            All of these things are simple markdown files.  They live in the
         | 
| 98 | 
            +
            projects we are working on, and by treating our writing as a structured
         | 
| 99 | 
            +
            exercise we are able to do a lot more things with it than just read it.
         | 
| 100 | 
            +
             | 
| 101 | 
            +
            For example we can do:
         | 
| 102 | 
            +
             | 
| 103 | 
            +
            ```
         | 
| 104 | 
            +
            brief publish user stories /path/to/user-stories/*.html.md
         | 
| 105 | 
            +
            ```
         | 
| 106 | 
            +
             | 
| 107 | 
            +
            which is implemented by:
         | 
| 108 | 
            +
             | 
| 109 | 
            +
            ```ruby
         | 
| 110 | 
            +
            # brief.rb
         | 
| 111 | 
            +
             | 
| 112 | 
            +
            define "User Story" do
         | 
| 113 | 
            +
              meta do
         | 
| 114 | 
            +
                status
         | 
| 115 | 
            +
              end
         | 
| 116 | 
            +
             | 
| 117 | 
            +
              content do
         | 
| 118 | 
            +
                title "h1"
         | 
| 119 | 
            +
                paragraph "p:first-child"
         | 
| 120 | 
            +
                persona "p:first-child strong:1st-child"
         | 
| 121 | 
            +
                behavior "p:first-child strong:2nd-child"
         | 
| 122 | 
            +
                goal "p:first-child strong:3rd-child"
         | 
| 123 | 
            +
              end
         | 
| 124 | 
            +
             | 
| 125 | 
            +
              helpers do
         | 
| 126 | 
            +
                def create_github_issue
         | 
| 127 | 
            +
                  issue = github.create_issue(title: title, body: document.content)
         | 
| 128 | 
            +
                  set(issue_number: issue.number)
         | 
| 129 | 
            +
                end
         | 
| 130 | 
            +
              end
         | 
| 131 | 
            +
            end
         | 
| 132 | 
            +
             | 
| 133 | 
            +
            action "publish user stories" do |briefcase, models, options|
         | 
| 134 | 
            +
              user_stories = models
         | 
| 135 | 
            +
             | 
| 136 | 
            +
              user_stories.each do |user_story|
         | 
| 137 | 
            +
                if user_story.create_github_issue()
         | 
| 138 | 
            +
                  user_story.status = "published"
         | 
| 139 | 
            +
                  user_story.save
         | 
| 140 | 
            +
                end
         | 
| 141 | 
            +
              end
         | 
| 142 | 
            +
            end
         | 
| 143 | 
            +
            ```
         | 
| 144 | 
            +
             | 
| 145 | 
            +
            As you can see, Brief can be a way to make your Markdown writing efforts
         | 
| 146 | 
            +
            much more productive. 
         | 
    
        data/examples/blog/brief.rb
    CHANGED
    
    | @@ -20,35 +20,9 @@ define("Post") do | |
| 20 20 | 
             
                has_many :subheadings, "h2"
         | 
| 21 21 | 
             
              end
         | 
| 22 22 |  | 
| 23 | 
            -
               | 
| 23 | 
            +
              actions do
         | 
| 24 24 | 
             
                def publish(options={})
         | 
| 25 | 
            -
             | 
| 25 | 
            +
                  puts "The publish action"
         | 
| 26 26 | 
             
                end
         | 
| 27 27 | 
             
              end
         | 
| 28 | 
            -
             | 
| 29 | 
            -
              # Whenever we call post.save() and the status attribute changes
         | 
| 30 | 
            -
              # from draft to published, do something with the model
         | 
| 31 | 
            -
              on_status_change(:from => "draft", :to => "published") do |model|
         | 
| 32 | 
            -
                # Do Something
         | 
| 33 | 
            -
                # mail_service.send_html_email_campaign(model.to_html)
         | 
| 34 | 
            -
              end
         | 
| 35 | 
            -
            end
         | 
| 36 | 
            -
             | 
| 37 | 
            -
            # this creates a custom command in the brief CLI tool
         | 
| 38 | 
            -
            #
         | 
| 39 | 
            -
            # so when you run:
         | 
| 40 | 
            -
            #
         | 
| 41 | 
            -
            #   brief publish posts /path/to/*.html.md.
         | 
| 42 | 
            -
            #
         | 
| 43 | 
            -
            # the brief CLI will find models for the post files you reference,
         | 
| 44 | 
            -
            # and call whatever methods you want.
         | 
| 45 | 
            -
             | 
| 46 | 
            -
            action "publish posts" do |briefcase, models, options|
         | 
| 47 | 
            -
             | 
| 48 | 
            -
              say "== Publishing #{ models.length } posts"
         | 
| 49 | 
            -
             | 
| 50 | 
            -
              Array(models).each do |post|
         | 
| 51 | 
            -
                post.publish()
         | 
| 52 | 
            -
              end
         | 
| 53 28 | 
             
            end
         | 
| 54 | 
            -
             | 
    
        data/lib/brief.rb
    CHANGED
    
    | @@ -28,6 +28,13 @@ module Brief | |
| 28 28 |  | 
| 29 29 | 
             
              def self.load_commands
         | 
| 30 30 | 
             
                Dir[gem_root.join("brief","cli","**/*.rb")].each {|f| require(f) }
         | 
| 31 | 
            +
             | 
| 32 | 
            +
                # the instance methods which get defined with the helper
         | 
| 33 | 
            +
                Brief::Model.classes.each do |klass|
         | 
| 34 | 
            +
                  Array(klass.defined_actions).uniq.each do |action|
         | 
| 35 | 
            +
                    Brief::Util.create_method_dispatcher_command_for(action, klass)
         | 
| 36 | 
            +
                  end
         | 
| 37 | 
            +
                end
         | 
| 31 38 | 
             
              end
         | 
| 32 39 |  | 
| 33 40 | 
             
              def self.load_models(from_folder=nil)
         | 
| @@ -37,6 +44,7 @@ end | |
| 37 44 |  | 
| 38 45 | 
             
            require "brief/core_ext"
         | 
| 39 46 | 
             
            require "brief/version"
         | 
| 47 | 
            +
            require "brief/util"
         | 
| 40 48 | 
             
            require "brief/configuration"
         | 
| 41 49 | 
             
            require "brief/document/rendering"
         | 
| 42 50 | 
             
            require "brief/document/front_matter"
         | 
    
        data/lib/brief/model.rb
    CHANGED
    
    | @@ -13,9 +13,10 @@ module Brief | |
| 13 13 | 
             
                  include AccessorMethods
         | 
| 14 14 | 
             
                  include Persistence
         | 
| 15 15 |  | 
| 16 | 
            -
                  class_attribute :models, :after_initialization_hooks, : | 
| 16 | 
            +
                  class_attribute :models, :after_initialization_hooks, :defined_actions
         | 
| 17 17 |  | 
| 18 18 | 
             
                  self.models = Array(self.models).to_set
         | 
| 19 | 
            +
                  self.defined_actions = Array(self.defined_actions).to_set
         | 
| 19 20 |  | 
| 20 21 | 
             
                  class << self
         | 
| 21 22 | 
             
                    include Enumerable
         | 
| @@ -69,21 +70,7 @@ module Brief | |
| 69 70 |  | 
| 70 71 | 
             
                def self.finalize
         | 
| 71 72 | 
             
                  Virtus.finalize
         | 
| 72 | 
            -
             | 
| 73 | 
            -
                  classes.each do |klass|
         | 
| 74 | 
            -
                    klass.name ||= klass.to_s.split('::').last.humanize
         | 
| 75 | 
            -
                    klass.type_alias ||= klass.name.parameterize.gsub(/-/,'_')
         | 
| 76 | 
            -
             | 
| 77 | 
            -
                    klass.attribute_set.map(&:name).each do |attr|
         | 
| 78 | 
            -
                      klass.define_singleton_method("find_by_#{ attr }") do |value|
         | 
| 79 | 
            -
                        where(attr => value).first
         | 
| 80 | 
            -
                      end
         | 
| 81 | 
            -
                    end
         | 
| 82 | 
            -
             | 
| 83 | 
            -
                    klass.definition.apply_config
         | 
| 84 | 
            -
                  end
         | 
| 85 | 
            -
             | 
| 86 | 
            -
                  Brief::Repository.define_document_finder_methods
         | 
| 73 | 
            +
                  classes.each(&:finalize)
         | 
| 87 74 | 
             
                end
         | 
| 88 75 |  | 
| 89 76 | 
             
                def ==(other)
         | 
| @@ -95,24 +82,35 @@ module Brief | |
| 95 82 | 
             
                end
         | 
| 96 83 |  | 
| 97 84 | 
             
                module ClassMethods
         | 
| 98 | 
            -
                  def  | 
| 99 | 
            -
                     | 
| 85 | 
            +
                  def has_actions?
         | 
| 86 | 
            +
                    definition.has_actions?
         | 
| 100 87 | 
             
                  end
         | 
| 101 88 |  | 
| 102 | 
            -
                  def  | 
| 103 | 
            -
                     | 
| 104 | 
            -
             | 
| 89 | 
            +
                  def finalize
         | 
| 90 | 
            +
                    klass = self
         | 
| 91 | 
            +
             | 
| 92 | 
            +
                    klass.name ||= klass.to_s.split('::').last.humanize
         | 
| 93 | 
            +
                    klass.type_alias ||= klass.name.parameterize.gsub(/-/,'_')
         | 
| 94 | 
            +
             | 
| 95 | 
            +
                    klass.attribute_set.map(&:name).each do |attr|
         | 
| 96 | 
            +
                      unless klass.method_defined?("find_by_#{ attr }")
         | 
| 97 | 
            +
                        klass.define_singleton_method("find_by_#{ attr }") do |value|
         | 
| 98 | 
            +
                          where(attr => value).first
         | 
| 99 | 
            +
                        end
         | 
| 100 | 
            +
                      end
         | 
| 101 | 
            +
                    end
         | 
| 102 | 
            +
             | 
| 103 | 
            +
                    klass.definition.apply_config
         | 
| 105 104 |  | 
| 106 | 
            -
             | 
| 107 | 
            -
                    definition.send(:meta, options, &block)
         | 
| 105 | 
            +
                    Brief::Repository.define_document_finder_methods
         | 
| 108 106 | 
             
                  end
         | 
| 109 107 |  | 
| 110 | 
            -
                  def  | 
| 111 | 
            -
                     | 
| 108 | 
            +
                  def where(*args, &block)
         | 
| 109 | 
            +
                    Brief::DocumentMapper::Query.new(self).send(:where, *args)
         | 
| 112 110 | 
             
                  end
         | 
| 113 111 |  | 
| 114 | 
            -
                  def  | 
| 115 | 
            -
                     | 
| 112 | 
            +
                  def each(*args, &block)
         | 
| 113 | 
            +
                    Array(self.models).send(:each, *args, &block)
         | 
| 116 114 | 
             
                  end
         | 
| 117 115 |  | 
| 118 116 | 
             
                  def after_initialize(&block)
         | 
| @@ -144,7 +142,10 @@ module Brief | |
| 144 142 | 
             
                  end
         | 
| 145 143 |  | 
| 146 144 | 
             
                  def method_missing(meth, *args, &block)
         | 
| 147 | 
            -
                    if meth.to_s | 
| 145 | 
            +
                    if %w(meta content actions helpers).include?(meth.to_s)
         | 
| 146 | 
            +
                      definition.send(meth, &block)
         | 
| 147 | 
            +
                      finalize
         | 
| 148 | 
            +
                    elsif meth.to_s.match(/^on_(.*)_change$/)
         | 
| 148 149 | 
             
                      create_change_handler($1, *args, &block)
         | 
| 149 150 | 
             
                    else
         | 
| 150 151 | 
             
                      super
         | 
| @@ -27,7 +27,7 @@ module Brief | |
| 27 27 | 
             
                    create_model_class.tap do |k|
         | 
| 28 28 | 
             
                      k.send(:include, Brief::Model)
         | 
| 29 29 |  | 
| 30 | 
            -
                      k.definition  | 
| 30 | 
            +
                      k.definition ||= definition
         | 
| 31 31 |  | 
| 32 32 | 
             
                      k.name ||= name
         | 
| 33 33 | 
             
                      k.type_alias ||= type_alias
         | 
| @@ -40,21 +40,22 @@ module Brief | |
| 40 40 | 
             
                end
         | 
| 41 41 |  | 
| 42 42 | 
             
                def apply_config
         | 
| 43 | 
            +
                  # define a virtus attribute mapping
         | 
| 43 44 | 
             
                  metadata_schema.values.each do |settings|
         | 
| 44 | 
            -
                    if model_class.nil?
         | 
| 45 | 
            -
                      binding.pry
         | 
| 46 | 
            -
                    end
         | 
| 47 | 
            -
             | 
| 48 45 | 
             
                    model_class.send(:attribute, *(settings[:args]))
         | 
| 49 46 | 
             
                  end
         | 
| 50 47 |  | 
| 51 | 
            -
                   | 
| 52 | 
            -
             | 
| 53 | 
            -
             | 
| 48 | 
            +
                  # defined helpers adds an anonymous module include
         | 
| 49 | 
            +
                  Array(self.defined_helpers).each {|mod| model_class.send(:include, mod) }
         | 
| 50 | 
            +
             | 
| 51 | 
            +
                  model_class.defined_actions += Array(self.defined_actions)
         | 
| 52 | 
            +
                  true
         | 
| 54 53 | 
             
                end
         | 
| 55 54 |  | 
| 56 55 | 
             
                def create_model_class
         | 
| 57 | 
            -
                  model_namespace. | 
| 56 | 
            +
                  unless (model_namespace.const_get(type_alias.camelize) rescue nil)
         | 
| 57 | 
            +
                    model_namespace.const_set(type_alias.camelize, Class.new)
         | 
| 58 | 
            +
                  end
         | 
| 58 59 | 
             
                end
         | 
| 59 60 |  | 
| 60 61 | 
             
                def model_class
         | 
| @@ -75,6 +76,18 @@ module Brief | |
| 75 76 | 
             
                  instance_eval(&block)
         | 
| 76 77 | 
             
                end
         | 
| 77 78 |  | 
| 79 | 
            +
                def has_actions?
         | 
| 80 | 
            +
                  !@defined_actions.empty?
         | 
| 81 | 
            +
                end
         | 
| 82 | 
            +
             | 
| 83 | 
            +
                def actions(&block)
         | 
| 84 | 
            +
                  helpers(&block)
         | 
| 85 | 
            +
                end
         | 
| 86 | 
            +
             | 
| 87 | 
            +
                def defined_actions
         | 
| 88 | 
            +
                  Array(defined_helpers).map(&:instance_methods).flatten
         | 
| 89 | 
            +
                end
         | 
| 90 | 
            +
             | 
| 78 91 | 
             
                def helpers(&block)
         | 
| 79 92 | 
             
                  self.defined_helpers ||= []
         | 
| 80 93 |  | 
    
        data/lib/brief/util.rb
    ADDED
    
    | @@ -0,0 +1,36 @@ | |
| 1 | 
            +
            module Brief::Util
         | 
| 2 | 
            +
              def self.create_method_dispatcher_command_for(action, klass)
         | 
| 3 | 
            +
                identifier = "#{ action } #{ klass.type_alias.to_s.pluralize }"
         | 
| 4 | 
            +
             | 
| 5 | 
            +
                Object.class.class_eval do
         | 
| 6 | 
            +
                  command "#{identifier}" do |c|
         | 
| 7 | 
            +
                    c.syntax = "brief #{identifier}"
         | 
| 8 | 
            +
                    c.description = "run the #{identifier} command"
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                    c.action do |args, opts|
         | 
| 11 | 
            +
                      briefcase = Brief.case
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                      path_args = args.select {|arg| arg.is_a?(String) && arg.match(/\.md$/) }
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                      path_args.select! do |arg|
         | 
| 16 | 
            +
                        path = briefcase.repository.root.join(arg)
         | 
| 17 | 
            +
                        path.exist?
         | 
| 18 | 
            +
                      end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                      path_args.map! {|p| briefcase.repository.root.join(p) }
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                      models = path_args.map {|path| Brief::Document.new(path) }.map(&:to_model)
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                      if models.empty?
         | 
| 25 | 
            +
                        model_finder = c.name.to_s.split(' ').last
         | 
| 26 | 
            +
                        models = briefcase.send(model_finder)
         | 
| 27 | 
            +
                      end
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                      models.each do |model|
         | 
| 30 | 
            +
                        model.send(action)
         | 
| 31 | 
            +
                      end
         | 
| 32 | 
            +
                    end
         | 
| 33 | 
            +
                  end rescue nil
         | 
| 34 | 
            +
                end
         | 
| 35 | 
            +
              end
         | 
| 36 | 
            +
            end
         | 
    
        data/lib/brief/version.rb
    CHANGED
    
    
| @@ -15,13 +15,13 @@ define "User Story" do | |
| 15 15 | 
             
                goal "p strong:third-child"
         | 
| 16 16 | 
             
              end
         | 
| 17 17 |  | 
| 18 | 
            -
               | 
| 18 | 
            +
              actions do
         | 
| 19 19 | 
             
                def defined_helper_method
         | 
| 20 20 | 
             
                  true
         | 
| 21 21 | 
             
                end
         | 
| 22 | 
            -
              end
         | 
| 23 | 
            -
            end
         | 
| 24 22 |  | 
| 25 | 
            -
             | 
| 26 | 
            -
             | 
| 23 | 
            +
                def custom_action
         | 
| 24 | 
            +
                  true
         | 
| 25 | 
            +
                end
         | 
| 26 | 
            +
              end
         | 
| 27 27 | 
             
            end
         | 
| @@ -2,7 +2,8 @@ class Brief::Epic | |
| 2 2 | 
             
              include Brief::Model
         | 
| 3 3 |  | 
| 4 4 | 
             
              meta do
         | 
| 5 | 
            -
                title | 
| 5 | 
            +
                title
         | 
| 6 | 
            +
                subheading
         | 
| 6 7 | 
             
                status String, :in => %w(draft published)
         | 
| 7 8 | 
             
              end
         | 
| 8 9 |  | 
| @@ -13,4 +14,9 @@ class Brief::Epic | |
| 13 14 | 
             
                  has_many :user_stories, "h2" => "title", "p:first-child" => "paragraph"
         | 
| 14 15 | 
             
                end
         | 
| 15 16 | 
             
              end
         | 
| 17 | 
            +
             | 
| 18 | 
            +
              actions do
         | 
| 19 | 
            +
                def custom_action
         | 
| 20 | 
            +
                end
         | 
| 21 | 
            +
              end
         | 
| 16 22 | 
             
            end
         | 
| @@ -31,6 +31,11 @@ describe "The Brief Model" do | |
| 31 31 | 
             
                  set = Brief::Model::UserStory.attribute_set.map(&:name)
         | 
| 32 32 | 
             
                  expect(set).to include(:title, :status, :epic_title)
         | 
| 33 33 | 
             
                end
         | 
| 34 | 
            +
             | 
| 35 | 
            +
                it "has attribute setters" do
         | 
| 36 | 
            +
                  story = Brief::Model::UserStory.new
         | 
| 37 | 
            +
                  expect(story).to respond_to(:title=)
         | 
| 38 | 
            +
                end
         | 
| 34 39 | 
             
              end
         | 
| 35 40 |  | 
| 36 41 | 
             
              context "Class Definitions" do
         | 
| @@ -55,6 +60,12 @@ describe "The Brief Model" do | |
| 55 60 | 
             
                  set = Brief::Epic.attribute_set.map(&:name)
         | 
| 56 61 | 
             
                  expect(set).to include(:path, :document, :title, :status)
         | 
| 57 62 | 
             
                end
         | 
| 63 | 
            +
             | 
| 64 | 
            +
                it "has attribute setters" do
         | 
| 65 | 
            +
                  epic = Brief::Epic.new
         | 
| 66 | 
            +
                  expect(epic).to respond_to(:title=)
         | 
| 67 | 
            +
                  expect(epic).to respond_to(:subheading=)
         | 
| 68 | 
            +
                end
         | 
| 58 69 | 
             
              end
         | 
| 59 70 |  | 
| 60 71 | 
             
              context "Briefcase Finders" do
         | 
| @@ -81,4 +92,14 @@ describe "The Brief Model" do | |
| 81 92 | 
             
                  expect(epic.extracted.title).to eq("Blueprint Epic Example")
         | 
| 82 93 | 
             
                end
         | 
| 83 94 | 
             
              end
         | 
| 95 | 
            +
             | 
| 96 | 
            +
              context "Actions and Helpers" do
         | 
| 97 | 
            +
                it "uses the actions block to define CLI dispatchers" do
         | 
| 98 | 
            +
                  expect(epic.class.defined_actions).to include(:custom_action)
         | 
| 99 | 
            +
                end
         | 
| 100 | 
            +
             | 
| 101 | 
            +
                it "users the actions block to define CLI dispatchers (dsl)" do
         | 
| 102 | 
            +
                  expect(user_story.class.defined_actions).to include(:custom_action)
         | 
| 103 | 
            +
                end
         | 
| 104 | 
            +
              end
         | 
| 84 105 | 
             
            end
         | 
    
        metadata
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: brief
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 1. | 
| 4 | 
            +
              version: 1.1.0
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Jonathan Soeder
         | 
| @@ -215,11 +215,13 @@ executables: | |
| 215 215 | 
             
            extensions: []
         | 
| 216 216 | 
             
            extra_rdoc_files: []
         | 
| 217 217 | 
             
            files:
         | 
| 218 | 
            +
            - ".gitignore"
         | 
| 218 219 | 
             
            - Gemfile
         | 
| 219 220 | 
             
            - Gemfile.lock
         | 
| 220 221 | 
             
            - LICENSE.txt
         | 
| 221 222 | 
             
            - README.md
         | 
| 222 223 | 
             
            - Rakefile
         | 
| 224 | 
            +
            - TUTORIAL.md
         | 
| 223 225 | 
             
            - bin/brief
         | 
| 224 226 | 
             
            - brief.gemspec
         | 
| 225 227 | 
             
            - examples/blog/brief.rb
         | 
| @@ -229,7 +231,6 @@ files: | |
| 229 231 | 
             
            - lib/brief/briefcase.rb
         | 
| 230 232 | 
             
            - lib/brief/cli/change.rb
         | 
| 231 233 | 
             
            - lib/brief/cli/init.rb
         | 
| 232 | 
            -
            - lib/brief/cli/publish.rb
         | 
| 233 234 | 
             
            - lib/brief/cli/write.rb
         | 
| 234 235 | 
             
            - lib/brief/configuration.rb
         | 
| 235 236 | 
             
            - lib/brief/core_ext.rb
         | 
| @@ -241,7 +242,9 @@ files: | |
| 241 242 | 
             
            - lib/brief/dsl.rb
         | 
| 242 243 | 
             
            - lib/brief/model.rb
         | 
| 243 244 | 
             
            - lib/brief/model/definition.rb
         | 
| 245 | 
            +
            - lib/brief/model/persistence.rb
         | 
| 244 246 | 
             
            - lib/brief/repository.rb
         | 
| 247 | 
            +
            - lib/brief/util.rb
         | 
| 245 248 | 
             
            - lib/brief/version.rb
         | 
| 246 249 | 
             
            - spec/fixtures/example/brief.rb
         | 
| 247 250 | 
             
            - spec/fixtures/example/docs/concept.html.md
         | 
| @@ -256,6 +259,7 @@ files: | |
| 256 259 | 
             
            - spec/lib/brief/document_spec.rb
         | 
| 257 260 | 
             
            - spec/lib/brief/dsl_spec.rb
         | 
| 258 261 | 
             
            - spec/lib/brief/model_spec.rb
         | 
| 262 | 
            +
            - spec/lib/brief/persistence_spec.rb
         | 
| 259 263 | 
             
            - spec/lib/brief/repository_spec.rb
         | 
| 260 264 | 
             
            - spec/spec_helper.rb
         | 
| 261 265 | 
             
            - spec/support/test_helpers.rb
         | 
| @@ -298,6 +302,7 @@ test_files: | |
| 298 302 | 
             
            - spec/lib/brief/document_spec.rb
         | 
| 299 303 | 
             
            - spec/lib/brief/dsl_spec.rb
         | 
| 300 304 | 
             
            - spec/lib/brief/model_spec.rb
         | 
| 305 | 
            +
            - spec/lib/brief/persistence_spec.rb
         | 
| 301 306 | 
             
            - spec/lib/brief/repository_spec.rb
         | 
| 302 307 | 
             
            - spec/spec_helper.rb
         | 
| 303 308 | 
             
            - spec/support/test_helpers.rb
         | 
    
        data/lib/brief/cli/publish.rb
    DELETED
    
    | 
            File without changes
         |