beastie 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
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