beastie 0.3.0 → 0.4.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 6f24bc36744a8be167db9a4331e94ecabcab1554
4
- data.tar.gz: dd0690cf2c6cf69b88a7db87ec05dc5d6084eaa7
3
+ metadata.gz: 55a0236d7397dc7dd609866c8626939671311a40
4
+ data.tar.gz: 4c2bbd746c30ddf062e5e93dcd07585479db165a
5
5
  SHA512:
6
- metadata.gz: 9a1650acd6767af4d3eeef5e74e71da0024732badab0d388493bd8540f6805418993139db9025621a2e2252e97369eede0429b6012d765e9558585578440f178
7
- data.tar.gz: 7ecedb24b9f338fe7ebe4b546dd3df8742b94e231855614ef62e782ad46c5c265cd0e1107f364aff017bd8180b2d411ffbf49fdbfdee95dc8b4e1d6a7d61cc69
6
+ metadata.gz: a7b1ca0ad1891cfe1b6f977aa540c61637b1a080d6aaefb51f6b2c68762327ca8ece38b671a8a01286e136380f24505ebeffd6c689157af5af512d7db1ae8932
7
+ data.tar.gz: a29e31ed196abfdf13c16fcc4e227de4b09028ff007acdf90f8be02f88c4dc3c0471307b151d31a1a15eda4852f7cc78e5f2c7a2f7c105d885b7caf0d7655b34
data/README.textile CHANGED
@@ -54,7 +54,7 @@ For this reason, from version 0.3, @beastie@ supports the following two options
54
54
  For instance:
55
55
 
56
56
  <pre>
57
- beastie -d ~/issues show
57
+ beastie show -d ~/issues
58
58
  </pre>
59
59
 
60
60
  will show all issues stored in the @~/issue@ directory.
@@ -80,13 +80,33 @@ For instance, if @.beastie_projects@ contains:
80
80
  then
81
81
 
82
82
  <pre>
83
- $ beastie -p beastie show
83
+ $ beastie show -p beastie
84
84
  </pre>
85
85
 
86
86
  will show all the issues stored in the @/Users/guest/beastie_issues@ directory.
87
87
 
88
88
  Use only one of @-d@ or @-p@; if you do not, @-d@ has precedence.
89
89
 
90
+ h2. Filtering
91
+
92
+ Beastie has support for filtering data, using the @--where@ option. The option takes as argument an expression (written in Ruby), defining what issues have to be printed.
93
+
94
+ For instance:
95
+
96
+ <pre>
97
+ beastie list --where "status == 'open'"
98
+ </pre>
99
+
100
+ will show only the @open@ issues. More complex expressions can be defined, using Boolean operators:
101
+
102
+ <pre>
103
+ beastie list --where "status == 'open' and priority >= 4"
104
+ </pre>
105
+
106
+ will show open issues with priority greater or equal to 4.
107
+
108
+ Notice that the expression passes as argument to @--where@ is evaluated in Ruby, so any Ruby expression will work.
109
+
90
110
  h2. Remarks and Warnings
91
111
 
92
112
  Beastie generates human-readable filenames, following the convention "Jekyll":http://jekyllrb.com has for blog posts. Selecting issues using filenames, however, is a bit clumsy and to simplify operations @beastie@ assigns a number to each issue, which can be used to reference them. The number can be seen with the @list@ command and depends upon the order in which issues are listed in the directory. Thus *the same issue might be assigned a different id over time*, if the order in which files are read changes (e.g., if a new back-dated issue is added by hand).
@@ -97,20 +117,12 @@ Beastie does not perform syntax checks when reading data. This can be changed b
97
117
 
98
118
  Beastie asks various information about a bug. Change the @ISSUE_FIELDS@ variable, if you are not happy with the default fieldset.
99
119
 
100
- Beastie does not have fancy sorting and filtering functions. The unix commands @sort@ and @grep@ can be reasonable work-arounds. For instance the list of open bugs can be gotten with:
101
-
102
- <pre>
103
- beastie list | grep open
104
- </pre>
105
-
106
- To sort issues by priority:
120
+ Sorting its on the way (but not yet implemented). Use the power of Unix for that. For instance:
107
121
 
108
122
  <pre>
109
123
  beastie list | grep -v "^ID" | sort -n -k 4
110
124
  </pre>
111
125
 
112
- Exceptions apply.
113
-
114
126
 
115
127
  h2. Similar solutions
116
128
 
@@ -123,11 +135,11 @@ So... why did I re-invent the wheel?
123
135
  # a "programmable" fieldset (see @lib/beastie/issue.rb@)
124
136
  # keeping the solution simple (280 lines of ruby code, according to @sloccount@)
125
137
 
126
- Use @beastie@! According to @sloccount@, you using a software which costed $8,033! (... as you might guess, COCOMO does not work well for small systems.)
138
+ Use @beastie@! According to @sloccount@, you will be using, for free, a software which costed $4,490 to produce! (This is less than the cost of v 0.3, which was estimated at $8,000. Jekyll mercenary, in fact, lowered the number of lines of code and the costs estimated with COCOMO.)
127
139
 
128
140
  h2. Author
129
141
 
130
- Adolfo Villafiorita
142
+ "Adolfo Villafiorita":http://ict4g.org/home/profile/Adolfo_Villafiorita.html
131
143
 
132
144
  h2. License
133
145
 
data/beastie.gemspec CHANGED
@@ -20,4 +20,6 @@ Gem::Specification.new do |spec|
20
20
 
21
21
  spec.add_development_dependency "bundler", "~> 1.3"
22
22
  spec.add_development_dependency "rake"
23
+
24
+ spec.add_dependency "mercenary", "~> 0.3"
23
25
  end
data/bin/beastie CHANGED
@@ -1,6 +1,231 @@
1
1
  #!/usr/bin/env ruby
2
-
2
+
3
+ require 'mercenary'
3
4
  require_relative '../lib/beastie'
4
5
 
5
- Beastie::Runner.run(ARGV)
6
+ Mercenary.program(:beastie) do |p|
7
+ EDITOR = "emacsclient"
8
+
9
+ p.version Beastie::VERSION
10
+ p.description 'A simple command-line bug-tracking system'
11
+ p.syntax "beastie <subcommand> [options] [arguments]"
12
+
13
+ p.option 'directory', '--directory DIR', '-d DIR', 'operate on DIR'
14
+ p.option 'project', '--project PRJ', '-p PRJ', 'operate on project PRJ'
15
+
16
+ p.command(:new) do |c|
17
+ c.syntax "new"
18
+ c.description "create a new issue"
19
+
20
+ c.action do |args, options|
21
+ if args.size != 0
22
+ puts "beastie error: too many arguments.\n"
23
+ puts p.to_s
24
+ exit 1
25
+ end
26
+
27
+ dir = dest_dir options
28
+ issue = Beastie::Issue.new dir
29
+ issue.ask
30
+ issue.save
31
+ puts "Issue saved to #{issue.full_filename}."
32
+ end
33
+ end
34
+
35
+ p.command(:nedit) do |c|
36
+ c.syntax("nedit title")
37
+ c.description("create an issue template and edit it with default editor.")
38
+
39
+ c.action do |args, options|
40
+ title = args.join(" ") # get all arguments (so that no " are necessary)
41
+
42
+ if title == ""
43
+ puts "beastie error: please specify the title of the issue.\n"
44
+ puts p.to_s
45
+ exit 1
46
+ end
47
+
48
+ dir = dest_dir options
49
+ issue = Beastie::Issue.new dir
50
+ issue.set_fields title
51
+ issue.save
52
+ system("#{editor_cmd} #{issue.full_filename}")
53
+ end
54
+ end
55
+
56
+ p.command(:edit) do |c|
57
+ c.syntax "edit N"
58
+ c.description "edit issue number N (where N is the output of the list command)"
59
+
60
+ c.action do |args, options|
61
+ dir = dest_dir options
62
+ issue = Beastie::Issue.new dir
63
+
64
+ if args.size != 1 or not digits_only(args[0]) or args[0].to_i > issue.count
65
+ puts "beastie error: please specify a valid identifier.\n\n"
66
+ puts p.to_s
67
+ exit 1
68
+ end
69
+
70
+ issue_no = args[0].to_i
71
+ system("#{editor_cmd} #{issue.id_to_full_filename issue_no}")
72
+ end
73
+ end
74
+
75
+ p.command(:list) do |c|
76
+ c.syntax "list"
77
+ c.description "list all issues"
78
+
79
+ c.option "where", "-w COND", "--where COND", "filter according to condition"
80
+
81
+ c.action do |_, options|
82
+ dir = dest_dir options
83
+
84
+ issue = Beastie::Issue.new dir
85
+ issue.list options["where"] || "true" # it is a string because we eval the argument
86
+ end
87
+ end
88
+
89
+ p.command(:show) do |c|
90
+ c.syntax "show N"
91
+ c.description "show issue with id N (where N is the output of the list command)"
92
+
93
+ c.action do |args, options|
94
+ dir = dest_dir options
95
+ issue = Beastie::Issue.new dir
96
+
97
+ if args.size != 1 or not digits_only(args[0]) or args[0].to_i > issue.count
98
+ puts "beastie error: please specify an issue.\n"
99
+ puts p.to_s
100
+ exit 1
101
+ end
102
+
103
+ issue_no = args[0].to_i
104
+ system("cat #{issue.id_to_full_filename issue_no}")
105
+ end
106
+ end
107
+
108
+ p.command(:change) do |c|
109
+ c.syntax "change N f v"
110
+ c.description "change value of field 'f' to 'v' in issue N"
111
+ c.alias "modify"
112
+
113
+ c.action do |args, options|
114
+ dir = dest_dir options
115
+ issue = Beastie::Issue.new dir
116
+
117
+ if args.size != 3 or not digits_only(args[0]) or args[0].to_i > issue.count
118
+ puts "beastie error: could not parse command line.\n"
119
+ puts p.to_s
120
+ exit 1
121
+ end
122
+
123
+ issue_no = args[0].to_i
124
+ field = args[1]
125
+ value = args[2]
126
+
127
+ issue.load_n issue_no
128
+ issue.change field, value
129
+ issue.save
130
+ puts "Issue #{issue_no} has now #{field} set to #{value}."
131
+ end
132
+ end
133
+
134
+ p.command(:close) do |c|
135
+ c.syntax "close N"
136
+ c.description "shortcut for 'change N status closed'"
137
+
138
+ c.action do |args, options|
139
+ dir = dest_dir options
140
+ issue = Beastie::Issue.new dir
141
+
142
+ if args.size != 1 or not digits_only(args[0]) or args[0].to_i > issue.count
143
+ puts "beastie error: please specify an issue.\n"
144
+ puts p.to_s
145
+ exit 1
146
+ end
147
+
148
+ issue_no = args[0].to_i
149
+ issue.load_n issue_no
150
+ issue.change "status", "closed"
151
+ issue.save
152
+ puts "Issue #{issue_no} is now closed."
153
+ end
154
+ end
155
+
156
+ p.command(:projects) do |c|
157
+ c.syntax "projects"
158
+ c.alias "list_projects"
159
+ c.description "list currently defined projects"
160
+
161
+ c.action do |_,_|
162
+ puts Beastie::ProjectList.to_s
163
+ end
164
+ end
165
+
166
+ p.command(:version) do |c|
167
+ c.syntax "version"
168
+ c.description "print version number (equivalent to beastie -v)"
169
+
170
+ c.action do |_,_|
171
+ puts "This is beastie version #{Beastie::VERSION}"
172
+ end
173
+ end
174
+
175
+ p.command(:help) do |c|
176
+ c.syntax "help"
177
+ c.description "print command usage information (equivalent to beastie -h)"
178
+
179
+ c.action do |_,_|
180
+ puts p.to_s
181
+ end
182
+ end
183
+
184
+ p.default_command(:help)
185
+
186
+ private
187
+
188
+ # define the directory in which we will operate
189
+ def self.dest_dir options
190
+ if options["project"] then
191
+ dir = Beastie::ProjectList.project_dir options["project"]
192
+
193
+ if dir == nil then
194
+ name = options["project"]
195
+ puts "beastie error: nothing known about project #{name}.\n"
196
+ puts ""
197
+ puts "add the following lines to #{Beastie::ProjectList::PROJECT_FILE}"
198
+ puts ""
199
+ puts "#{name}:"
200
+ puts " dir: <directory where #{name} issues live>"
201
+ exit 1
202
+ end
203
+ elsif options["directory"] then
204
+ dir = options["directory"]
205
+ else
206
+ dir = "."
207
+ end
208
+
209
+ if not Dir.exists?(dir)
210
+ puts "beastie error: the directory does not exist"
211
+ puts ""
212
+ puts "if you used -p, please check the #{Beastie::ProjectList::PROJECT_FILE} file"
213
+ exit 1
214
+ end
215
+
216
+ dir
217
+ end
218
+
219
+ # check if str is composed by digits only
220
+ def self.digits_only str
221
+ str.each_char.map { |x| x >= '0' and x <= '9'}.all?
222
+ end
223
+
224
+ # get an editor
225
+ def self.editor_cmd
226
+ shell_editor = `echo ${EDITOR}`.chomp
227
+ shell_editor == "" ? EDITOR : shell_editor
228
+ end
229
+
230
+ end
6
231
 
data/lib/beastie/issue.rb CHANGED
@@ -141,7 +141,7 @@ module Beastie
141
141
  end
142
142
 
143
143
  # list all issues in current directory
144
- def list
144
+ def list condition
145
145
  # print header
146
146
  printf "ID "
147
147
  REPORT_FIELDS.keys.each do |key|
@@ -155,11 +155,28 @@ module Beastie
155
155
  data = YAML.load_file(file)
156
156
  file_no += 1
157
157
 
158
- printf "%3d ", file_no
158
+ # create a string with all the bindings
159
+ assignments = ""
159
160
  REPORT_FIELDS.keys.each do |key|
160
- printf REPORT_FIELDS[key] + " ", data[key]
161
+ # not sure why, but using classes does not work..
162
+ # so I make them into strings
163
+ case data[key].class.to_s
164
+ when "Fixnum"
165
+ assignments << "#{key} = #{data[key]};"
166
+ when "String"
167
+ assignments << "#{key} = '#{data[key]}';"
168
+ when "Date"
169
+ assignments << "#{key} = Date.parse('#{data[key]}');"
170
+ end
171
+ end
172
+
173
+ if eval (assignments + condition) then
174
+ printf "%3d ", file_no
175
+ REPORT_FIELDS.keys.each do |key|
176
+ printf REPORT_FIELDS[key] + " ", data[key]
177
+ end
178
+ printf "\n"
161
179
  end
162
- printf "\n"
163
180
  end
164
181
  end
165
182
 
@@ -14,6 +14,17 @@ module Beastie
14
14
  end
15
15
  end
16
16
 
17
+ # an overkill ... system("cat #{PROJECT_FILE}") could work equally well
18
+ def self.to_s
19
+ output = ""
20
+ projects = self.read
21
+ projects.keys.each do |key|
22
+ output << "#{key}:\n"
23
+ output << " dir: #{projects[key]["dir"]}\n"
24
+ end
25
+ output
26
+ end
27
+
17
28
  private
18
29
 
19
30
  def self.read
@@ -1,3 +1,3 @@
1
1
  module Beastie
2
- VERSION = "0.3.0"
2
+ VERSION = "0.4.0"
3
3
  end
data/lib/beastie.rb CHANGED
@@ -1,210 +1,3 @@
1
- require 'pathname'
2
- require 'optparse'
3
-
4
1
  require_relative "beastie/version"
5
2
  require_relative "beastie/issue"
6
3
  require_relative "beastie/project_list"
7
-
8
- module Beastie
9
-
10
- # add an option to optparser to accept an existing pathname as option
11
- OptionParser.accept(Pathname) do |pn|
12
- Pathname.new(pn) if pn
13
- raise OptionParser::InvalidArgument, pn if not Dir.exist?(pn)
14
- end
15
-
16
- class Runner
17
- # the editor to use with the edit command
18
- EDITOR = "emacsclient"
19
-
20
- def self.run(args)
21
-
22
- # default directory is ".", unless -p is specified
23
- dir = "."
24
- OptionParser.new do |opts|
25
- opts.on("-p", "--project name", String,
26
- "Use project's dir for operations") do |name|
27
- dir = ProjectList.project_dir name
28
-
29
- if dir == nil then
30
- puts "beastie error: nothing known about project #{name}.\n"
31
- puts ""
32
- puts "add the following lines to #{ProjectList::PROJECT_FILE}"
33
- puts ""
34
- puts "#{name}:"
35
- puts " dir: <directory where #{name} issues live>"
36
- exit 1
37
- end
38
- end
39
-
40
- opts.on("-d", "--directory name", String,
41
- "Use this directory for operations") do |name|
42
- dir = name
43
- end
44
- end.order!.parse!
45
-
46
- if not Dir.exists?(dir)
47
- puts "beastie error: the directory does not exist"
48
- puts ""
49
- puts "if you used -p, please check the #{ProjectList::PROJECT_FILE} file"
50
- exit 1
51
- end
52
-
53
- command = args[0]
54
- args.shift
55
-
56
- case command
57
-
58
- when "new"
59
- if args.size != 0
60
- puts "beastie error: too many arguments.\n"
61
- help
62
- exit 1
63
- end
64
-
65
- issue = Issue.new dir
66
- issue.ask
67
- issue.save
68
- puts "Issue saved to #{issue.full_filename}."
69
-
70
- when "nedit"
71
- title = args.join(" ") # get all arguments (so that no " are necessary)
72
-
73
- if title == ""
74
- puts "beastie error: please specify the title of the issue.\n"
75
- help
76
- exit 1
77
- end
78
-
79
- issue = Issue.new dir
80
- issue.set_fields title
81
- issue.save
82
- system("#{editor_cmd} #{issue.full_filename}")
83
-
84
- when "edit"
85
- issue = Issue.new dir
86
-
87
- if args.size != 1 or not digits_only(args[0]) or args[0].to_i > issue.count
88
- puts "beastie error: please specify a valid identifier.\n\n"
89
- help
90
- exit 1
91
- end
92
-
93
- issue_no = args[0].to_i
94
- system("#{editor_cmd} #{issue.id_to_full_filename issue_no}")
95
-
96
- when "show"
97
- issue = Issue.new dir
98
-
99
- if args.size != 1 or not digits_only(args[0]) or args[0].to_i > issue.count
100
- puts "beastie error: please specify an issue.\n"
101
- help
102
- exit 1
103
- end
104
-
105
- issue_no = args[0].to_i
106
- system("cat #{issue.id_to_full_filename issue_no}")
107
-
108
- when "modify", "change"
109
- issue = Issue.new dir
110
-
111
- if args.size != 3 or not digits_only(args[0]) or args[0].to_i > issue.count
112
- puts "beastie error: could not parse command line.\n"
113
- help
114
- exit 1
115
- end
116
-
117
- issue_no = args[0].to_i
118
- field = args[1]
119
- value = args[2]
120
-
121
- issue.load_n issue_no
122
- issue.change field, value
123
- issue.save
124
- puts "Issue #{issue_no} has now #{field} set to #{value}."
125
-
126
- when "close"
127
- issue = Issue.new dir
128
-
129
- if args.size != 1 or not digits_only(args[0]) or args[0].to_i > issue.count
130
- puts "beastie error: please specify an issue.\n"
131
- help
132
- exit 1
133
- end
134
-
135
- issue_no = args[0].to_i
136
- issue.load_n issue_no
137
- issue.change "status", "closed"
138
- issue.save
139
- puts "Issue #{issue_no} is now closed."
140
-
141
- when "list"
142
- issue = Issue.new dir
143
- issue.list
144
-
145
- when "help"
146
- help
147
-
148
- when "version"
149
- puts "beastie version #{VERSION}"
150
-
151
- else
152
- help
153
- end
154
-
155
- end
156
-
157
- private
158
-
159
- def self.help
160
- puts <<-eos
161
- beastie [-p <project> | -d <dir>] <command> [<args>]
162
-
163
- A simple command-line bug-tracking system
164
-
165
- Global options:
166
- -p <project> (--project) command will operate on <project> (*)
167
- -d <dir> (--directory) command will operate on directory <dir>
168
-
169
- Commands:
170
- new create a new issue in current directory
171
- nedit title create an issue template and edit it with default editor
172
- list list all issues stored in current directory
173
- edit N edit issue with id N (where N is the output of the list command)
174
- show N show issue with id N (where N is the output of the list command)
175
- change N f v change value of field 'f' to 'v' in id N
176
- modify N f v change value of field 'f' to 'v' in id N
177
- close N shortcut for 'change N status closed'
178
- version print version number
179
-
180
- (*) To use this option, create a file #{ProjectList::PROJECT_FILE} containing
181
- entries in the form:
182
-
183
- <project1>:
184
- dir: <dir1>
185
- <project2>:
186
- dir: <dir2>
187
-
188
- For instance:
189
-
190
- beastie:
191
- dir: /Users/guest/beastie
192
-
193
- (in which case -p beastie is equivalent to -d /Users/guest/beastie)
194
- eos
195
- end
196
-
197
- # check if str is composed by digits only
198
- def self.digits_only str
199
- str.each_char.map { |x| x >= '0' and x <= '9'}.all?
200
- end
201
-
202
- # get an editor
203
- def self.editor_cmd
204
- shell_editor = `echo ${EDITOR}`.chomp
205
- shell_editor == "" ? EDITOR : shell_editor
206
- end
207
-
208
- end
209
-
210
- end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: beastie
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Adolfo Villafiorita
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-02-06 00:00:00.000000000 Z
11
+ date: 2014-06-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -38,6 +38,20 @@ dependencies:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: mercenary
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '0.3'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '0.3'
41
55
  description: A command-line issue and bug tracking system
42
56
  email:
43
57
  - adolfo.villafiorita@me.com
@@ -78,7 +92,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
78
92
  version: '0'
79
93
  requirements: []
80
94
  rubyforge_project:
81
- rubygems_version: 2.2.1
95
+ rubygems_version: 2.2.2
82
96
  signing_key:
83
97
  specification_version: 4
84
98
  summary: A command-line issue and bug tracking system which uses a file per bug, yaml