rubyshelltools 0.0.2 → 0.0.3

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.
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