rubyshelltools 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -1,18 +1,34 @@
1
1
  Ruby Shell Tools
2
2
  ================
3
3
 
4
- RST Version 0.0.1 is an experimental Ruby2-gem by Andreas Altendorfer <andreas@altendorfer.at>
4
+ RubyShellTools, RST is an experimental Ruby2-gem by Andreas Altendorfer <andreas@altendorfer.at>
5
+
6
+
7
+ Inspired by this [talk about nodoc][] and by the clean style of
8
+ [Martin's code][], I've playing around with Ruby2, Yard, and my idea of
9
+ clean code with this gem named 'RubyShellTools' (short RST, but this
10
+ name wasn't available at rubygems anymore ;-)
11
+
12
+ Since bash-history isn't always enough persistent for my daily work, I deal with the idea to create a kinda 'central toolbox' for my shell. RST represents the first steps in this direction. I'm not sure if the 'project' will survive, tho. I'll give it a try.
13
+
14
+ The first pushed version features a very simple 'ls' and 'calendar'-command. The plan is to play around with the structure of the gem until I'm satisfied and feel comfortable to start implementing more features. There's a ton of ideas what RST could do, I'm just not sure what it shall do. Let's see ...
15
+
5
16
 
6
17
  Install from rubygems.org
7
18
  -------------------------
19
+
20
+ Find the gem at [RubyGems.org][]
8
21
 
9
22
  gem install rubyshelltools
23
+ export RST_DATA=$HOME/.rst # default: GEM_PATH/rubyshelltools/data
24
+ export RST_ENV=production # defaults: development
25
+ rst --help
10
26
 
11
27
 
12
- Clone from Github
13
- -----------------
28
+ Clone/Fork from Github
29
+ ----------------------
14
30
 
15
- You can clone the project from **[Github](https://github.com/iboard/rst)**
31
+ You can clone from or fork the project at => [Github][]
16
32
 
17
33
  git clone git://github.com/iboard/rst.git
18
34
 
@@ -32,7 +48,7 @@ Usage
32
48
 
33
49
  see file EXAMPLES.md:
34
50
 
35
- * [At Github](https://github.com/iboard/rst/blob/master/assets/docs/examples.md#examples)
51
+ * [EXAMPLES on Github][]
36
52
  * [loacal copy](./file.examples.html)
37
53
 
38
54
  or run
@@ -48,39 +64,77 @@ Documentation
48
64
  run `yard; open doc/index.html` to build the rdocs and open
49
65
  it in your browser.
50
66
 
51
- The documentation can be found also at
52
- [dav.iboard.cc](http://dav.iboard.cc/container/rst-doc)
67
+ The latest version is online at my [DAV-server][] too.
68
+
69
+ Browsing the code
70
+ -----------------
71
+
72
+ **modules**
73
+
74
+ Modules are the core of this project. Within the directory
75
+ `lib/modules` you'll find
76
+
77
+ * calendar # Everything about Calendars
78
+ * calendar # The Calendar-module and -class
79
+ * eventable # Eventable API (module to make a class an event)
80
+ * calendar_event # CalendarEvent-class
81
+
82
+ * persistent # Make things persistent
83
+ * persistent # The Persistent-Module defines Persistentable/API
84
+ * store # The abstract Store-class
85
+ * memory_store # Store-descendant for a non-persistent memory-store
86
+ * disk_store # Store-descendant using ruby-PStore to save to disk
87
+
88
+
89
+ **command-line implementation**
90
+
91
+ * ./rst.rb # Defines global Constants and the Logger
92
+ * ./lib/rst.rb # Defines the class RstCommand used for the
93
+ # command-line-implementation
94
+ * ./lib/load.rb # requires all necessary files
95
+ # used by bin/rst and spec/spec_helper.rb
96
+ * ./bin/rst # Loads the library and instantiates a
97
+ # RstCommand-object
98
+
99
+ **RstCommand**
100
+
101
+ Can handle two commands by now:
102
+
103
+ _ls_,
104
+ the directory-listing, is coded
105
+ inline and does a simple Dir for the given wildcards.
106
+
107
+ _print_calendar_,
108
+ opens the calendar-file (all calendars are stored in one file) and acts on the calendar
109
+ named by the --name parameter. It uses _DiskStore_ to make the calendars
110
+ persistent.
111
+
112
+ cal = find_calendar( Persistent::DiskStore.new(CALENDAR_FILE) )
113
+ cal.list_days(options[:from], options[:to], options[:show_empty]).compact.join("\n")
114
+
115
+
53
116
 
54
117
  TDD
55
118
  ---
56
119
 
57
120
  And as always we are **green**
58
121
 
59
- You can find the current output of [simplecov][] at [dav.iboard.cc](http://dav.iboard.cc/container/rst-coverage)
60
-
61
-
62
- > $ rake
63
- >
64
- > Finished in _a few_ seconds
65
- >
66
- > _n_ examples, 0 failures
67
- >
68
- > Coverage report generated for RSpec to rst/coverage. _n_ / _n+-0_ LOC (**100.0%**) covered.
69
- >
70
- > $ yard
71
- >
72
- > Files: _n_
73
- >
74
- > Modules: _n_ ( 0 undocumented)
75
- >
76
- > Classes: _n_ ( 0 undocumented)
77
- >
78
- > Constants: _n_ ( 0 undocumented)
79
- >
80
- > Methods: _n_ ( 0 undocumented)
81
- >
82
- > **100.00% documented**
122
+ See the current [coverage output][] (generated with [simplecov][])
123
+
124
+ Running `rake` and `yard` from the project-directory the output should include
125
+ the following lines ...
126
+
127
+ Finished in _a few_ seconds
128
+ _n_ examples, *0* failures
129
+ Coverage report generated for RSpec to rst/coverage. _n_ / _n+-0_ LOC (**100.0%**) covered.
130
+ **100.00% documented**
131
+
132
+ To run specs you can use rake-tasks
83
133
 
134
+ rake [test] # Run Module-specs w/o command-line calls (default)
135
+ rake all # Run all tests including specs/commands
136
+ rake commands # Run command-specs only (slower because of system-calls)
137
+ rake modules # Run module-specs only
84
138
 
85
139
  License
86
140
  =======
@@ -99,3 +153,10 @@ Copyright
99
153
 
100
154
 
101
155
  [simplecov]: http://github.com/colszowka/simplecov
156
+ [RubyGems.org]: https://rubygems.org/gems/rubyshelltools
157
+ [coverage output]: http://dav.iboard.cc/container/rst-coverage
158
+ [Github]: https://github.com/iboard/rst
159
+ [EXAMPLES on Github]: https://github.com/iboard/rst/blob/master/assets/docs/examples.md#examples
160
+ [DAV-Server]: http://dav.iboard.cc/container/rst-doc
161
+ [talk about nodoc]: http://www.youtube.com/watch?v=tCw7CpRvYOE
162
+ [Martin's code]: https://github.com/snusnu
@@ -90,3 +90,21 @@ The full set of parameters is
90
90
  * --empty ...... show empty lines
91
91
  * --no-empty ... show no empty lines (default)
92
92
 
93
+
94
+ Save defaults
95
+ =============
96
+
97
+ You can save options with `--save-defaults` and then cal rst without
98
+ options to execute it with command and saved-options
99
+
100
+ $ rst calendar --from '1964-01-01' --to today --save-defaults
101
+ Defaults Saved
102
+ Mon, Aug 31 1964: Birthday Andreas Altendorfer
103
+
104
+ $ rst
105
+ Mon, Aug 31 1964: Birthday Andreas Altendorfer
106
+
107
+ You can delete saved options with `--clear-defaults` or list saved
108
+ options with `--list-defaults`
109
+
110
+
data/bin/rst CHANGED
@@ -8,4 +8,5 @@ include RST
8
8
 
9
9
 
10
10
  # Run rst from commandline
11
- puts RstCommand.new(ARGV).run
11
+ output = RstCommand.new(ARGV).run
12
+ puts output unless output.blank?
@@ -0,0 +1,9 @@
1
+
2
+ # Monkeypatch string with some useful methods
3
+ class String
4
+ # @return [Boolean] - true if self is empty or filled with spaces only
5
+ def blank?
6
+ self.strip == ''
7
+ end
8
+ end
9
+
@@ -1,6 +1,25 @@
1
1
  module RST
2
2
 
3
3
  # Exception thrown when an abstract method is called
4
- class AbstractMethodCallError < NotImplementedError; end
4
+ class AbstractMethodCallError < NotImplementedError
5
+
6
+ def initialize message='Please define '
7
+ _message = [ message, format_backtrace(caller_locations(2,1)), 'Called from:']
8
+ (3..24).to_a.each do |n|
9
+ _message << format_backtrace(caller_locations(n,1))
10
+ end
11
+ super(_message.join(" => "))
12
+ end
13
+
14
+ private
15
+
16
+ # Output the filename and line of a backtrace-step
17
+ # @param [Array] l - one caller_location-line
18
+ # @return [String]
19
+ def format_backtrace(l)
20
+ "%s in %s:%d" % [l[0].label,File.basename(l[0].path),l[0].lineno]
21
+ end
22
+
23
+ end
5
24
 
6
25
  end
data/lib/load.rb CHANGED
@@ -21,6 +21,7 @@ unless defined? LIB_LOADED
21
21
 
22
22
  $LOAD_PATH.unshift(File.expand_path('../core_extensions',__FILE__))
23
23
  require 'numeric'
24
+ require 'string'
24
25
  require 'mutex'
25
26
 
26
27
  $LOAD_PATH.unshift(File.expand_path('../errors',__FILE__))
@@ -68,6 +68,8 @@ module RST
68
68
  include Persistent::Persistentable
69
69
  include CalendarHelper
70
70
 
71
+ # @group public api
72
+
71
73
  attr_reader :name, :start_date, :end_date, :events
72
74
 
73
75
  # @param [String] _name Name and persistent-id of this calendar.
@@ -129,7 +131,6 @@ module RST
129
131
  end
130
132
 
131
133
 
132
- private
133
134
  # All events on the given date
134
135
  # @param [Date] date
135
136
  # @return [Array] of [CalendarEvents]
@@ -137,19 +138,17 @@ module RST
137
138
  events.select { |event| event.event_date == date }
138
139
  end
139
140
 
140
- # Convert strings to a date
141
- # @param [Date|Time|String] param - default is 'today'
142
- # @return [Date|Time]
143
- def parse_date_param(param=Date.today)
144
- ensure_date(param)
145
- end
141
+ # @endgroup
142
+
143
+ private
144
+ # @group private api
146
145
 
147
146
  # Output date and Events on this date in one line
148
147
  # @param [Date] _date
149
148
  # @param [Boolean] show_empty - do output lines with no events
150
149
  # @return [String]
151
150
  def format_events_for(_date,show_empty=false)
152
- if show_empty || (_line=event_headlines_for(_date)) != ''
151
+ if (_line=event_headlines_for(_date)) != '' || show_empty
153
152
  "%s: %s" % [_date.strftime(DEFAULT_DATE_FORMAT), _line]
154
153
  end
155
154
  end
@@ -161,6 +160,15 @@ module RST
161
160
  events_on(_date).map(&:event_headline).join(' + ').strip
162
161
  end
163
162
 
163
+ # @endgroup
164
+
165
+ # Convert strings to a date
166
+ # @param [Date|Time|String] param - default is 'today'
167
+ # @return [Date|Time]
168
+ def parse_date_param(param=Date.today)
169
+ ensure_date(param)
170
+ end
171
+
164
172
  end
165
173
 
166
174
  end
@@ -3,7 +3,8 @@ module RST
3
3
 
4
4
  # Inject Eventable to any Class to make it event-able in a Calendar
5
5
  # You have to define a method :event_headline for the class
6
- # in order to list the event in a Calendar
6
+ # in order to list the event in a Calendar.
7
+ #
7
8
  # @example
8
9
  #
9
10
  # class Birthday < Struct.new(:name,:dob)
@@ -17,7 +18,7 @@ module RST
17
18
  # def event_headline
18
19
  # "It's #{name}'s Birthday"
19
20
  # end
20
- # end
21
+ # end
21
22
  #
22
23
  # @see RST::Calendar::Calendar
23
24
  module Eventable
@@ -56,9 +56,16 @@ module RST
56
56
  s[object.id] = object
57
57
  end
58
58
  end
59
-
59
+
60
60
  private
61
61
 
62
+ # @param [Object] object - the object to be removed.
63
+ def remove_object(object)
64
+ @store.transaction do |s|
65
+ s.delete(object.id)
66
+ end
67
+ end
68
+
62
69
  # Initialize a PStore-instance
63
70
  # @see store_path
64
71
  def setup_backend
@@ -75,10 +82,17 @@ module RST
75
82
  #
76
83
  # ~/.rst-data/development/store.data
77
84
  #
78
- # if no environment-variables defined, the defaulsts will be STOREPATH and 'development'
85
+ # if no environment-variables defined, the defaults will be STOREPATH and 'development'
79
86
  # @see STOREPATH
80
87
  # @return [String]
81
88
  def store_path
89
+ @store_path ||= build_store_path
90
+ end
91
+
92
+ # build the path from ENV-vars and create the directory
93
+ # if necessary
94
+ # @return [String] full path of data-file for current environment
95
+ def build_store_path
82
96
  prefix = ENV['RST_DATA'] || RST::STOREPATH
83
97
  env = ENV['RST_ENV'] || 'development'
84
98
  _dir = File.join( prefix, env )
@@ -86,12 +100,6 @@ module RST
86
100
  File.join(_dir, filename)
87
101
  end
88
102
 
89
- # @param [Object] object - the object to be removed.
90
- def remove_object(object)
91
- @store.transaction do |s|
92
- s.delete(object.id)
93
- end
94
- end
95
103
  end
96
104
 
97
105
  end
@@ -71,20 +71,20 @@ module RST
71
71
  # @return Enumerable
72
72
  # @abstract Overwrite in descendants thus it returns an Enumerable of all objects in the store
73
73
  def all
74
- raise AbstractMethodCallError.new("Please, overwrite #{__callee__} in #{self.class.to_s}")
74
+ raise AbstractMethodCallError.new
75
75
  end
76
76
 
77
77
  # Delete the store
78
78
  # @abstract - override this method in descendants thus the store removes all objects.
79
79
  def delete!
80
- raise AbstractMethodCallError.new("Please, overrwrite #{__callee__} in #{self.class.to_s}")
80
+ raise AbstractMethodCallError.new
81
81
  end
82
82
 
83
83
  # Find and update or add an object to the store
84
84
  # @param [Object] object
85
85
  # @abstract - override in other StoreClasses
86
86
  def update(object)
87
- raise AbstractMethodCallError.new("Please, overrwrite #{__callee__} in #{self.class.to_s}")
87
+ raise AbstractMethodCallError.new
88
88
  end
89
89
 
90
90
  # @endgroup
@@ -114,19 +114,19 @@ module RST
114
114
  # objects-array, PStore, database-connection,...
115
115
  # @abstract - Overwrite in descendants thus they initialize the store.
116
116
  def setup_backend
117
- raise AbstractMethodCallError.new("Please override method :setup_backend in class #{self.class.to_s}")
117
+ raise AbstractMethodCallError.new
118
118
  end
119
119
 
120
120
  # Make sure the current state of objects is stored
121
121
  # @abstract - Overwrite in descendants thus every object gets persistently stored.
122
122
  def sync_store
123
- raise AbstractMethodCallError.new("Please override method :sync_store in class #{self.class.to_s}")
123
+ raise AbstractMethodCallError.new
124
124
  end
125
125
 
126
126
  # @param [Object] object
127
127
  # @abstract - override in concrete StoreClasses
128
128
  def remove_object(object)
129
- raise AbstractMethodCallError.new("Please, overrwrite #{__callee__} in #{self.class.to_s}")
129
+ raise AbstractMethodCallError.new
130
130
  end
131
131
 
132
132
  end
data/lib/rst.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  require 'optparse'
2
2
  require 'ostruct'
3
+ require_relative './modules/persistent/persistent'
3
4
 
4
5
  # # Ruby Shell Tools main namespace RST
5
6
  #
@@ -41,7 +42,10 @@ module RST
41
42
 
42
43
  # Initialize the Command-runner with arguments and parse them.
43
44
  def initialize(args)
45
+ load_defaults
44
46
  parse_options(args)
47
+ @command ||= args.shift
48
+ @files = args
45
49
  end
46
50
 
47
51
  # Call 'run_options' and 'run_command', reject empty returns and join
@@ -62,7 +66,6 @@ module RST
62
66
  # @see #run_options
63
67
  # @see #run_option
64
68
  def parse_options(args)
65
- @options = DEFAULT_OPTIONS
66
69
  OptionParser.new do |opts|
67
70
  opts.banner = 'Usage: rst [COMMAND [COMMAND ....]] [options] [FILES..]'
68
71
 
@@ -108,6 +111,18 @@ module RST
108
111
  @options[:show_empty] = show
109
112
  end
110
113
 
114
+ opts.on('--save-defaults', 'Save given params as defaults') do |v|
115
+ @options[:save_defaults] = v
116
+ end
117
+
118
+ opts.on('--list-defaults', 'list saved defaults') do |v|
119
+ @options[:list_defaults] = v
120
+ end
121
+
122
+ opts.on('--clear-defaults', 'Save given params as defaults') do |v|
123
+ @options[:clear_defaults] = v
124
+ end
125
+
111
126
  opts.separator 'Commands:'
112
127
 
113
128
  opts.separator <<-EOT
@@ -140,11 +155,12 @@ module RST
140
155
  # @see #command
141
156
  # @return [String]
142
157
  def run_command
143
- case @command=ARGV.shift
158
+ case @command
144
159
  when nil, 'nil', 'null'
145
160
  ''
146
161
  when 'ls'
147
- directory_listing(ARGV.empty? ? ['*'] : ARGV)
162
+ @files << '*' if @files.empty?
163
+ directory_listing( @files )
148
164
  when 'cal', 'calendar'
149
165
  print_calendar
150
166
  else
@@ -196,6 +212,12 @@ module RST
196
212
  list_calendars
197
213
  when 'delete_calendar'
198
214
  delete_calendar
215
+ when 'save_defaults'
216
+ save_defaults
217
+ when 'list_defaults'
218
+ list_defaults
219
+ when 'clear_defaults'
220
+ clear_defaults
199
221
  else
200
222
  nil #noop ignore unknown options likely it's a param for an argument
201
223
  end
@@ -240,7 +262,7 @@ module RST
240
262
  puts "Binary : #{$0}"
241
263
  puts "Command: #{command}"
242
264
  puts "Options: #{options.map(&:inspect).join(', ')}"
243
- puts "Files : #{ARGV.any? ? ARGV[1..-1].join(', ') : ''}"
265
+ puts "Files : #{@files.join(', ')}"
244
266
  end
245
267
 
246
268
  # @group HELPERS
@@ -274,6 +296,47 @@ module RST
274
296
  end
275
297
  end
276
298
 
299
+ # Save the given command and options as defaults
300
+ def save_defaults
301
+ store = Persistent::DiskStore.new('defaults')
302
+ options.delete(:save_defaults)
303
+ defaults = Defaults.new( command, options )
304
+ store << defaults
305
+ "Defaults saved"
306
+ end
307
+
308
+ # Load Defaults
309
+ def load_defaults
310
+ @options||=DEFAULT_OPTIONS
311
+ store = Persistent::DiskStore.new('defaults')
312
+ _defaults = store.find('defaults')
313
+ if _defaults
314
+ @command = _defaults.command
315
+ @options.merge! _defaults.options
316
+ end
317
+ end
318
+
319
+ # List saved defaults
320
+ def list_defaults
321
+ store = Persistent::DiskStore.new('defaults')
322
+ defaults = store.find('defaults')
323
+ "Command: #{defaults.command}\nOptions:\n#{list_options(defaults.options)}" if defaults
324
+ end
325
+
326
+ # delete saved defaults
327
+ def clear_defaults
328
+ store = Persistent::DiskStore.new('defaults')
329
+ store.delete!
330
+ end
331
+
332
+ # print options
333
+ # @param [Hash] _options
334
+ def list_options(_options)
335
+ _options.map { |_o|
336
+ "--#{_o[0]} #{_o[1]}"
337
+ }.join("\n")
338
+ end
339
+
277
340
  end
278
341
 
279
342
  # @group HELPER CLASSES
@@ -290,6 +353,26 @@ module RST
290
353
  class EventOptions < Struct.new(:date,:label,:calendar_name,)
291
354
  end
292
355
 
356
+ # Defaults Store
357
+ # @api private
358
+ class Defaults
359
+ include Persistent::Persistentable
360
+
361
+ attr_reader :command
362
+ attr_reader :options
363
+
364
+ def id
365
+ 'defaults'
366
+ end
367
+
368
+ # @param [String] command
369
+ # @param [Hash] options
370
+ def initialize(command,options)
371
+ @command = command
372
+ @options = options
373
+ end
374
+ end
375
+
293
376
 
294
377
 
295
378
  end
data/rst.rb CHANGED
@@ -3,7 +3,7 @@ require 'logger'
3
3
  # # Ruby Shell Tools Top-level file
4
4
  module RST
5
5
  # Gem-version
6
- VERSION = '0.0.2'
6
+ VERSION = '0.0.3'
7
7
 
8
8
  # Path to the docs used by the software
9
9
  DOCS = File.expand_path('../assets/docs', __FILE__)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubyshelltools
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-03-17 00:00:00.000000000 Z
12
+ date: 2013-03-29 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: redcarpet
@@ -71,6 +71,7 @@ files:
71
71
  - ./rst.rb
72
72
  - lib/core_extensions/mutex.rb
73
73
  - lib/core_extensions/numeric.rb
74
+ - lib/core_extensions/string.rb
74
75
  - lib/errors/store_errors.rb
75
76
  - lib/load.rb
76
77
  - lib/modules/calendar/calendar.rb