ghaki-namer 2011.11.30.1

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2010 Gerald Kalafut
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.
data/README ADDED
@@ -0,0 +1,23 @@
1
+ = Ghaki Namer = Automatic file naming
2
+
3
+ Ghaki Namer is a series of helpers that allow file naming by a set pattern.
4
+
5
+ == Download
6
+
7
+ The latest version of Ghaki Namer can be found at
8
+
9
+ * git@github.com:ghaki/ghaki-namer.git
10
+
11
+ == Installation
12
+
13
+ The preferred method of installing Ghaki Namer is through its GEM file.
14
+
15
+ % [sudo] gem install ghaki-namer-1.0.0.gem
16
+
17
+ == License
18
+
19
+ Ghaki Namer is released under the MIT license.
20
+
21
+ == Support
22
+
23
+ Contact mailto:gerald@kalafut.org
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 2011.11.30.1
@@ -0,0 +1,80 @@
1
+ ############################################################################
2
+ module Ghaki
3
+ module Namer
4
+ class Base
5
+
6
+ ######################################################################
7
+ TIME_STAMP_FMT = '%Y%m%d_%H%M%S'
8
+ RAND_STAMP_MAX = 65536 # FFFF+1
9
+ RAND_STAMP_FMT = '%04x'
10
+
11
+ ######################################################################
12
+ attr_accessor :time_stamp, :rand_stamp, :rand_stamp_max,
13
+ :ticket_generator
14
+
15
+ ######################################################################
16
+ def initialize opts={}
17
+ @time_stamp = opts[:time_stamp] || Time.now
18
+ @rand_stamp_max = opts[:rand_stamp_max] || RAND_STAMP_MAX
19
+ @rand_stamp = opts[:rand_stamp] || rand(@rand_stamp_max)
20
+ @ticket_generator = opts[:ticket_generator]
21
+ end
22
+
23
+ ######################################################################
24
+ def parse_names *get_pile
25
+ put_pile = []
26
+ get_pile.each do |item|
27
+ _parse_item put_pile, item
28
+ end
29
+ put_pile
30
+ end
31
+
32
+ ######################################################################
33
+ def ticket
34
+ @ticket ||= parse_names( *@ticket_generator).join('')
35
+ end
36
+
37
+ ######################################################################
38
+ def debug_dump out_file
39
+ out_file.box 'debug ' + self.class.to_s
40
+ out_file.reindent({
41
+ :time_stamp => self.time_stamp,
42
+ :rand_stamp => self.rand_stamp,
43
+ :rand_stamp_max => self.rand_stamp_max,
44
+ :ticket_generator => self.ticket_generator,
45
+ }.inspect)
46
+ end
47
+
48
+ ######################################################################
49
+ ######################################################################
50
+ private
51
+
52
+ ######################################################################
53
+ def _parse_item put_pile, item
54
+ case item
55
+ when String then put_pile.push(item)
56
+ when :time_stamp then put_pile.push( @time_stamp.strftime(TIME_STAMP_FMT) )
57
+ when :rand_stamp then put_pile.push( RAND_STAMP_FMT % @rand_stamp )
58
+ when Array then _parse_complex put_pile, *item
59
+ when Proc then put_pile.push( item.call() )
60
+ else
61
+ raise ArgumentError, "Invalid Path Generator: #{item.class}"
62
+ end
63
+ end
64
+
65
+ ######################################################################
66
+ def _parse_complex put_pile, item, *info
67
+ case item
68
+ when :time_stamp then put_pile.push( @time_stamp.strftime(info[0]) )
69
+ when :rand_stamp then put_pile.push( info[0] % @rand_stamp )
70
+ when :format then put_pile.push( info[0] % info[1] )
71
+ when Proc then put_pile.push( item.call( *info ) )
72
+ else
73
+ raise ArgumentError, "Invalid Path Generator: #{item.class}"
74
+ end
75
+ end
76
+
77
+ end # class
78
+ end # namespace
79
+ end # package
80
+ ############################################################################
@@ -0,0 +1,3 @@
1
+ module Ghaki
2
+ class NamerError < RuntimeError; end
3
+ end
@@ -0,0 +1,13 @@
1
+ require 'ghaki/app/plugin'
2
+ require 'ghaki/namer/files/base'
3
+
4
+ module Ghaki #:nodoc:
5
+ module Namer #:nodoc:
6
+ module Files #:nodoc:
7
+
8
+ class App < Ghaki::App::Plugin
9
+ app_plugin_make Base, :file_namer
10
+ app_plugin_link :file_namer
11
+ end
12
+
13
+ end end end
@@ -0,0 +1,142 @@
1
+ require 'fileutils'
2
+ require 'ghaki/namer/base'
3
+
4
+ module Ghaki #:nodoc:
5
+ module Namer #:nodoc:
6
+ module Files #:nodoc:
7
+
8
+ class Base < Namer::Base
9
+
10
+ ######################################################################
11
+ attr_accessor :path_generator, :base_generator,
12
+ :suffix_map, :filename_map
13
+
14
+ ######################################################################
15
+ def initialize opts={} ; super opts
16
+ @suffix_map = {}
17
+ @filename_map = {}
18
+ @path_generator = opts[:path_generator] || []
19
+ @base_generator = opts[:base_generator] || []
20
+ end
21
+
22
+ ######################################################################
23
+ def debug_dump out_file; super
24
+ out_file.puts( {
25
+ :suffix_map => self.suffix_map,
26
+ :path_generator => self.path_generator,
27
+ :base_generator => self.base_generator,
28
+ :filename_map => self.filename_map,
29
+ }.inspect )
30
+ end
31
+
32
+ ######################################################################
33
+ def generate_filename key
34
+ cur_path = parse_names( *@path_generator )
35
+ cur_base = parse_names( *@base_generator ).
36
+ push( @suffix_map[key] ).join('.')
37
+ File.join( cur_path, cur_base )
38
+ end
39
+
40
+ ######################################################################
41
+ def create_working_dirs opts={}
42
+ @filename_map.values.each do |fname|
43
+ ::FileUtils.mkdir_p( File.dirname(fname), opts )
44
+ end
45
+ self
46
+ end
47
+
48
+ ######################################################################
49
+ # RESERVE FILE NAMES
50
+ ######################################################################
51
+
52
+ #---------------------------------------------------------------------
53
+ def reserve_file token, new_suffix
54
+ old_suffix = @suffix_map[token]
55
+ if old_suffix.nil?
56
+ @suffix_map[token] = new_suffix
57
+ elsif old_suffix != new_suffix
58
+ raise NamerError, "Inconsistent File Extension: #{token.to_s} (#{old_suffix}/#{new_suffix})"
59
+ end
60
+ end
61
+
62
+ #---------------------------------------------------------------------
63
+ def reserve_files list
64
+ list.each do |key,val| reserve_file key, val end
65
+ self
66
+ end
67
+
68
+ ######################################################################
69
+ # PUT FILENAMES USING OPTS
70
+ ######################################################################
71
+
72
+ #---------------------------------------------------------------------
73
+ def opt_put_file opts, token
74
+ put_file token, opts[token] if opts.has_key?(token)
75
+ end
76
+
77
+ #---------------------------------------------------------------------
78
+ def opt_put_files opts, *tokens
79
+ tokens.each do |token| opt_put_file token, opts end
80
+ end
81
+
82
+ ######################################################################
83
+ # PUT FILENAMES DIRECTLY
84
+ ######################################################################
85
+
86
+ #---------------------------------------------------------------------
87
+ def put_file token, new_fname
88
+ old_fname = @filename_map[token]
89
+ if old_fname.nil?
90
+ @filename_map[token] = new_fname
91
+ elsif old_fname != new_fname
92
+ raise NamerError, "Inconsistent Filenaming: #{token.to_s}"
93
+ end
94
+ new_fname
95
+ end
96
+
97
+ #---------------------------------------------------------------------
98
+ def put_files list
99
+ list.each do |key,val| put_file key, val end
100
+ self
101
+ end
102
+
103
+ ######################################################################
104
+ # FREEZE FILENAMES
105
+ ######################################################################
106
+
107
+ #---------------------------------------------------------------------
108
+ def freeze_file token
109
+ @filename_map[token] || put_file( token, generate_filename( token ) )
110
+ end
111
+
112
+ #---------------------------------------------------------------------
113
+ def freeze_files tokens
114
+ tokens.each do |token| freeze_file token end
115
+ self
116
+ end
117
+
118
+ #####################################################################
119
+ alias_method :get_file, :freeze_file
120
+
121
+ ######################################################################
122
+ # ASSIGNING FILE NAMES
123
+ ######################################################################
124
+
125
+ def assign_file token, suffix
126
+ reserve_file token, suffix
127
+ freeze_file token
128
+ end
129
+
130
+ ######################################################################
131
+ def assign_files list
132
+ list.each do |key,val| assign_file key, val end
133
+ self
134
+ end
135
+
136
+ ######################################################################
137
+ def file_named? token
138
+ @filename_map[token].nil?
139
+ end
140
+
141
+ end
142
+ end end end
@@ -0,0 +1,13 @@
1
+ require 'ghaki/app/mixable'
2
+ require 'ghaki/namer/files/app'
3
+
4
+ module Ghaki #:nodoc:
5
+ module Namer #:nodoc:
6
+ module Files #:nodoc:
7
+
8
+ module Mixin
9
+ include Ghaki::App::Mixable
10
+ app_mixin_accessor App, :file_namer
11
+ end
12
+
13
+ end end end
@@ -0,0 +1,88 @@
1
+ ############################################################################
2
+ require 'ghaki/namer/base'
3
+
4
+ ############################################################################
5
+ module Ghaki module Namer module BaseTesting
6
+ describe Ghaki::Namer::Base do
7
+
8
+ ########################################################################
9
+ TIME_VAL = Time.at(1269258809) # "2010/03/22 04:53:29"
10
+ TIME_FMT = TIME_VAL.strftime(Ghaki::Namer::Base::TIME_STAMP_FMT)
11
+ RAND_VAL = 32456
12
+ RAND_FMT = Ghaki::Namer::Base::RAND_STAMP_FMT % RAND_VAL
13
+
14
+ ########################################################################
15
+ context 'object' do
16
+ subject {Ghaki::Namer::Base.new }
17
+ it { should respond_to :time_stamp }
18
+ it { should respond_to :rand_stamp }
19
+ it { should respond_to :rand_stamp_max }
20
+ it { should respond_to :parse_names }
21
+ it { should respond_to :ticket }
22
+ it { should respond_to :ticket_generator }
23
+ end
24
+
25
+ ########################################################################
26
+ describe '#new' do
27
+
28
+ context 'with specific options' do
29
+ MY_NOW = Time.now.to_i - 100
30
+ MY_NUM = 100
31
+ MY_MAX = 100
32
+ subject do
33
+ Ghaki::Namer::Base.new({
34
+ :time_stamp => MY_NOW,
35
+ :rand_stamp => MY_NUM,
36
+ :rand_stamp_max => MY_MAX,
37
+ })
38
+ end
39
+ specify { subject.time_stamp.should == MY_NOW }
40
+ specify { subject.rand_stamp.should == MY_NUM }
41
+ specify { subject.rand_stamp_max.should == MY_MAX }
42
+ end
43
+ end
44
+
45
+ ########################################################################
46
+ describe '#parse_names' do
47
+ subject do
48
+ Ghaki::Namer::Base.new({
49
+ :time_stamp => TIME_VAL,
50
+ :rand_stamp => RAND_VAL,
51
+ })
52
+ end
53
+ it 'should see time default' do
54
+ subject.parse_names(:time_stamp)[0].should == TIME_FMT
55
+ end
56
+ it 'should see rand default' do
57
+ subject.parse_names(:rand_stamp)[0].should == RAND_FMT
58
+ end
59
+ it 'should see time with format' do
60
+ subject.parse_names( [:time_stamp,'%Y/%m/%d'] )[0].should == '2010/03/22'
61
+ end
62
+ it 'should see rand with format' do
63
+ fmt = '%08d'
64
+ aft = fmt % RAND_VAL
65
+ subject.parse_names( [:rand_stamp,fmt] )[0].should == aft
66
+ end
67
+ it 'should see static values' do
68
+ out = subject.parse_names('ghaki','log')
69
+ out[0].should == 'ghaki'
70
+ out[1].should == 'log'
71
+ end
72
+ it 'should do complex formats' do
73
+ subject.parse_names( [:format,'%0.3s','phxlb13'] )[0].should == 'phx'
74
+ end
75
+ it 'should do simple lambdas' do
76
+ str = 'quack'
77
+ fun = lambda do 'quack' end
78
+ subject.parse_names(fun)[0].should == str
79
+ end
80
+ it 'should do complex lambdas' do
81
+ fun = lambda do |major,minor| major + '_' + minor end
82
+ subject.parse_names( [fun,'moo','12'] )[0].should == 'moo_12'
83
+ end
84
+ end
85
+
86
+ end
87
+ end end end
88
+ ############################################################################
@@ -0,0 +1,40 @@
1
+ ############################################################################
2
+ require 'ghaki/app/engine'
3
+ require 'ghaki/namer/files/app'
4
+
5
+ ############################################################################
6
+ module Ghaki module App module EngineTesting
7
+
8
+ SOURCE_MOD = Ghaki::Namer::Files::Base
9
+ TARGET_MOD = Ghaki::App::Engine
10
+
11
+ describe TARGET_MOD do
12
+
13
+ ######################################################################
14
+ context 'singleton' do
15
+ subject { TARGET_MOD.instance }
16
+ [ :file_namer, :file_namer_opts,
17
+ :file_namer=, :file_namer_opts=,
18
+ ].each do |token|
19
+ it { should respond_to token }
20
+ end
21
+ end
22
+
23
+ ######################################################################
24
+ context 'singleton method' do
25
+
26
+ describe '#file_namer' do
27
+ subject { TARGET_MOD.instance.file_namer }
28
+ it { should be_an_instance_of(SOURCE_MOD) }
29
+ end
30
+
31
+ describe '#file_namer_opts' do
32
+ subject { TARGET_MOD.instance.file_namer_opts }
33
+ it { should be_an_instance_of(::Hash) }
34
+ end
35
+
36
+ end
37
+
38
+ end
39
+ end end end
40
+ ############################################################################
@@ -0,0 +1,36 @@
1
+ ############################################################################
2
+ require 'ghaki/namer/files/app'
3
+
4
+ ############################################################################
5
+ module Ghaki module Namer module Files module AppTesting
6
+
7
+ APP_MOD = Ghaki::Namer::Files::App
8
+ BASE_MOD = Ghaki::Namer::Files::Base
9
+
10
+ describe APP_MOD do
11
+ context 'singleton instance' do
12
+ subject { APP_MOD.instance }
13
+
14
+ it { should respond_to :file_namer }
15
+ it { should respond_to :file_namer= }
16
+ describe '#file_namer' do
17
+ subject { APP_MOD.instance.file_namer }
18
+ it { should be_an_instance_of(BASE_MOD) }
19
+ end
20
+
21
+ it { should respond_to :file_namer_opts }
22
+ it { should respond_to :file_namer_opts= }
23
+ describe '#file_namer_opts' do
24
+ subject { APP_MOD.instance.file_namer_opts }
25
+ it { should be_an_instance_of(::Hash) }
26
+ context 'defaults' do
27
+ # WORK GOES HERE
28
+ end
29
+ end
30
+
31
+ it { should respond_to :file_namer_defs }
32
+ it { should respond_to :file_namer_defs= }
33
+
34
+ end
35
+ end
36
+ end end end end
@@ -0,0 +1,75 @@
1
+ require 'ghaki/namer/files/base'
2
+
3
+ module Ghaki module Namer module Files module BaseTesting
4
+ BASE_MOD = Ghaki::Namer::Files::Base
5
+ describe BASE_MOD do
6
+
7
+ TIME_VAL = Time.at(1269258809).gmtime # "2010/03/22 11:53:29"
8
+ TIME_FMT = TIME_VAL.strftime(Ghaki::Namer::Base::TIME_STAMP_FMT)
9
+ RAND_VAL = 32456
10
+ RAND_FMT = Ghaki::Namer::Base::RAND_STAMP_FMT % RAND_VAL
11
+
12
+ ########################################################################
13
+ context 'object instance' do
14
+ subject { BASE_MOD.new }
15
+ it { should respond_to :create_working_dirs }
16
+ it { should respond_to :put_file }
17
+ it { should respond_to :put_files }
18
+ it { should respond_to :assign_file }
19
+ it { should respond_to :assign_files }
20
+ it { should respond_to :reserve_file }
21
+ it { should respond_to :reserve_files }
22
+ it { should respond_to :freeze_file }
23
+ it { should respond_to :freeze_files }
24
+ it { should respond_to :get_file }
25
+ end
26
+
27
+ ########################################################################
28
+ context 'name generation' do
29
+ subject do
30
+ BASE_MOD.new({
31
+ :time_stamp => TIME_VAL,
32
+ :rand_stamp => RAND_VAL,
33
+ :path_generator => [ '/ghaki/project', 'logs' ],
34
+ :base_generator => [:time_stamp]
35
+ })
36
+ end
37
+ describe '#reserve_file' do
38
+ it 'reserves file name' do
39
+ subject.reserve_file( :log_file, 'error.log' )
40
+ subject.get_file(:log_file).should == '/ghaki/project/logs/20100322_115329.error.log'
41
+ end
42
+ end
43
+ describe '#assign_file' do
44
+ it 'assign file name' do
45
+ subject.assign_file( :log_file, 'error.log' )
46
+ subject.get_file(:log_file).should == '/ghaki/project/logs/20100322_115329.error.log'
47
+ end
48
+ end
49
+ describe '#put_file' do
50
+ it 'stores file name' do
51
+ subject.put_file( :log_file, './error.txt' )
52
+ subject.get_file(:log_file).should == './error.txt'
53
+ end
54
+ end
55
+ end
56
+
57
+ ########################################################################
58
+ describe '#create_working_dirs' do
59
+ before(:all) do
60
+ @my_path = '/tmp/bogus'
61
+ @stor = BASE_MOD.new({
62
+ :path_generator => [@my_path],
63
+ }).assign_files({
64
+ :log_file => 'error.txt',
65
+ })
66
+ ::FileUtils.expects(:mkdir_p).with(@my_path,is_a(Hash)).once
67
+ end
68
+ it 'calls mkdir' do
69
+ @stor.create_working_dirs
70
+ end
71
+ end
72
+
73
+ end
74
+ end end end end
75
+ ############################################################################
@@ -0,0 +1,27 @@
1
+ ############################################################################
2
+ require 'ghaki/namer/files/mixin'
3
+
4
+ ############################################################################
5
+ module Ghaki module Namer module Files module MixinTesting
6
+ MIX_MOD = Ghaki::Namer::Files::Mixin
7
+ BAS_MOD = Ghaki::Namer::Files::Base
8
+ describe MIX_MOD do
9
+
10
+ class MyClass
11
+ include MIX_MOD
12
+ end
13
+
14
+ context 'including objects' do
15
+ subject { MyClass.new }
16
+ it { should respond_to :file_namer }
17
+ it { should respond_to :file_namer= }
18
+ end
19
+
20
+ describe '#file_namer' do
21
+ subject { MyClass.new.file_namer }
22
+ specify { subject.should be_an_instance_of(BAS_MOD) }
23
+ end
24
+
25
+ end
26
+ end end end end
27
+ ############################################################################
@@ -0,0 +1,6 @@
1
+ require 'mocha'
2
+
3
+ RSpec.configure do |cfg|
4
+ cfg.mock_with :mocha
5
+ cfg.color_enabled = true
6
+ end
metadata ADDED
@@ -0,0 +1,109 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ghaki-namer
3
+ version: !ruby/object:Gem::Version
4
+ version: 2011.11.30.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Gerald Kalafut
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-11-30 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: ghaki-app
16
+ requirement: &79714500 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: 2011.11.29.1
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *79714500
25
+ - !ruby/object:Gem::Dependency
26
+ name: rspec
27
+ requirement: &79714280 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: 2.4.0
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: *79714280
36
+ - !ruby/object:Gem::Dependency
37
+ name: mocha
38
+ requirement: &79714050 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ! '>='
42
+ - !ruby/object:Gem::Version
43
+ version: 0.9.12
44
+ type: :development
45
+ prerelease: false
46
+ version_requirements: *79714050
47
+ - !ruby/object:Gem::Dependency
48
+ name: rdoc
49
+ requirement: &79713820 !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: 3.9.4
55
+ type: :development
56
+ prerelease: false
57
+ version_requirements: *79713820
58
+ description: Series of helpers that allow file naming by a set pattern.
59
+ email: gerald@kalafut.org
60
+ executables: []
61
+ extensions: []
62
+ extra_rdoc_files:
63
+ - README
64
+ files:
65
+ - lib/ghaki/namer/error.rb
66
+ - lib/ghaki/namer/base.rb
67
+ - lib/ghaki/namer/files/mixin.rb
68
+ - lib/ghaki/namer/files/app.rb
69
+ - lib/ghaki/namer/files/base.rb
70
+ - README
71
+ - LICENSE
72
+ - VERSION
73
+ - spec/ghaki/namer/base_spec.rb
74
+ - spec/ghaki/namer/files/base_spec.rb
75
+ - spec/ghaki/namer/files/mixin_spec.rb
76
+ - spec/ghaki/namer/files/app_fnamer_spec.rb
77
+ - spec/ghaki/namer/files/app_engine_spec.rb
78
+ - spec/spec_helper.rb
79
+ homepage: http://ghaki.com/
80
+ licenses: []
81
+ post_install_message:
82
+ rdoc_options: []
83
+ require_paths:
84
+ - lib
85
+ required_ruby_version: !ruby/object:Gem::Requirement
86
+ none: false
87
+ requirements:
88
+ - - ! '>='
89
+ - !ruby/object:Gem::Version
90
+ version: '0'
91
+ required_rubygems_version: !ruby/object:Gem::Requirement
92
+ none: false
93
+ requirements:
94
+ - - ! '>='
95
+ - !ruby/object:Gem::Version
96
+ version: 1.3.6
97
+ requirements: []
98
+ rubyforge_project: ghaki-namer
99
+ rubygems_version: 1.8.10
100
+ signing_key:
101
+ specification_version: 3
102
+ summary: Automatic file naming
103
+ test_files:
104
+ - spec/ghaki/namer/base_spec.rb
105
+ - spec/ghaki/namer/files/base_spec.rb
106
+ - spec/ghaki/namer/files/mixin_spec.rb
107
+ - spec/ghaki/namer/files/app_fnamer_spec.rb
108
+ - spec/ghaki/namer/files/app_engine_spec.rb
109
+ - spec/spec_helper.rb