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
|