re-org 0.0.1

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.
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
4
+
5
+ group :test do
6
+ gem 'rake'
7
+ gem 'rspec'
8
+ end
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Waldemar Quevedo
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,56 @@
1
+ * ReOrg
2
+
3
+ An Org mode file organizer.
4
+
5
+ ** Motivation
6
+
7
+ Instead of having tons of sparsed Org mode files everywhere,
8
+ this project attemtps to give the Org mode writer a framework
9
+ to re-organize the files in a less chaotic manner.
10
+
11
+ ** Installation
12
+
13
+ =re-org= is distributed using =rubygems=:
14
+
15
+ #+begin_src sh
16
+ $ gem install re-org
17
+ #+end_src
18
+
19
+ ** Usage
20
+
21
+ The idea here is to have a pair of ~todo~ and ~done~ folders.
22
+ Writings that are still in progress would go into the ~todo~ folder
23
+ and those that are considered as finished can go into the ~done~ directory.
24
+
25
+ #+begin_src sh
26
+ re-org
27
+ #+end_src
28
+
29
+ (the name of these folders could depend of the project, and it marks the difference
30
+ between the drafts and finished folders.
31
+
32
+ For example, in Jekyll the name of these folders would be ~_drafts~
33
+ and ~_posts~.
34
+
35
+ - I suppose there is another kind of folder which works as the outline
36
+ of the work that is being done. (~_clockfiles~?). Maintenance of
37
+ this file is usually done per month from my experience.
38
+ ~re-org~ helps to create a new file by using the same template.
39
+
40
+ Digressions on the site itself also would go here.
41
+
42
+ These kind of entries are much more useful to post them to a site
43
+ (like ~org-remote~) where you can track and see them published on a per Headline basis
44
+ by using what is included in the ~PROPERTIES~ drawer and ~CLOCK~.
45
+
46
+ #+begin_src sh :results output
47
+ bundle exec ruby bin/re-org --help
48
+ #+end_src
49
+
50
+ ** Contributing
51
+
52
+ 1. Fork it
53
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
54
+ 3. Commit your changes (`git commit -am 'Added some feature'`)
55
+ 4. Push to the branch (`git push origin my-new-feature`)
56
+ 5. Create new Pull Request
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
3
+
4
+ require 'rspec/core'
5
+ require 'rspec/core/rake_task'
6
+
7
+ RSpec::Core::RakeTask.new(:spec) do |spec|
8
+ spec.pattern = FileList['spec/**/*_spec.rb']
9
+ spec.rspec_opts = ["--format", "documentation", "--colour"]
10
+ end
@@ -0,0 +1,10 @@
1
+ # -*- mode: org -*-
2
+
3
+ - [X] Create new file with current datetime
4
+ - [X] Put the current writings in =todo= directory
5
+ - [X] Allow to use different templates
6
+ - [ ] Completed and organized files go to the =done= folder.
7
+ - [ ] Make it possible to set a =templates= directory
8
+ - [ ] Load an Org mode file, do some changes to it, and then export it again to Org
9
+ + Needs work on this =org-ruby= branch: [[https://github.com/wallyqs/org-ruby/commits/feature/org-exporter][link]]
10
+ - [ ] Add examples to README.org
@@ -0,0 +1,32 @@
1
+ #!/usr/bin/env ruby
2
+ # -*- mode: ruby -*-
3
+ require 'docopt'
4
+ require 're-org'
5
+
6
+ doc = <<OPTIONS
7
+
8
+ re-org: A tool to help re-organize your texts written in Org mode
9
+
10
+ Usage:
11
+ re-org new <template> [--notebook=<notebook>] [--title=<title>]
12
+ re-org status [--notebook=<notebook>] [--count-keywords]
13
+ re-org templates [--name=<name>]
14
+
15
+ Options:
16
+
17
+ -h --help Show this screen.
18
+ --version Show this version.
19
+
20
+ OPTIONS
21
+
22
+ begin
23
+ require "pp"
24
+ cmd = Docopt::docopt(doc)
25
+ rescue Docopt::Exit => e
26
+ puts e.message
27
+ end
28
+
29
+ exit 1 unless cmd
30
+
31
+ o = ReOrg::Command.new(cmd)
32
+ o.execute!
@@ -0,0 +1,4 @@
1
+ require "re-org/version"
2
+ require "re-org/ext"
3
+ require "re-org/org_file"
4
+ require "re-org/command"
@@ -0,0 +1,126 @@
1
+ require 'erb'
2
+ require 'fileutils'
3
+ require 'org-ruby'
4
+
5
+ module ReOrg
6
+
7
+ class Command
8
+
9
+ CUSTOM_TEMPLATES_DIRS = ['templates', '_templates']
10
+
11
+ def initialize(options)
12
+ @options = options
13
+ end
14
+
15
+ def execute!
16
+ case true
17
+ when @options['new']
18
+ new_file
19
+ when @options['status']
20
+ show_status
21
+ when (@options['templates'] and not @options['--name'].nil?)
22
+ cat_template
23
+ when @options['templates']
24
+ show_templates
25
+ end
26
+ end
27
+
28
+ def show_status
29
+ puts '* Current Status'.yellow
30
+ puts ''
31
+ summary = Hash.new { |h,k| h[k] = {} }
32
+
33
+ org_files = Dir["#{OrgFile.todo_dir}/*"]
34
+ org_files.each do |org_file|
35
+ org_content = Orgmode::Parser.new(File.open(org_file).read)
36
+ if org_content.in_buffer_settings["NOTEBOOK"]
37
+ notebook_name = org_content.in_buffer_settings["NOTEBOOK"]
38
+ summary[notebook_name][:texts] ||= []
39
+ summary[notebook_name][:keywords] ||= {}
40
+ summary[notebook_name][:texts] << org_content
41
+ keywords = org_content.headlines.map { |h| h.keyword }
42
+ keywords.each do |k|
43
+ summary[notebook_name][:keywords][k] ||= 0
44
+ summary[notebook_name][:keywords][k] += 1
45
+ end
46
+ else
47
+ puts "Org file without notebook defined: #{org_file}".yellow
48
+ end
49
+ end
50
+
51
+ summary.each_pair do |notebook, info|
52
+ puts "- #{info[:texts].count} org files for '#{notebook}' notebook".green
53
+ info[:keywords].each do |keyword, count|
54
+ keyword ||= 'NONE'
55
+ puts "#{keyword}: #{count}"
56
+ end if @options["--count-keywords"]
57
+ info[:texts].each { |o| puts ["\t", o.headlines.first].join('')}
58
+ end
59
+ end
60
+
61
+ def show_templates
62
+ puts '* Default Templates'.yellow
63
+ puts ''
64
+ default_template_dir = File.expand_path("templates/", File.dirname(__FILE__))
65
+ default_templates = Dir["#{default_template_dir}/*"]
66
+ default_templates.each do |template|
67
+ puts "- #{File.basename(template)}\t(default)"
68
+ end
69
+
70
+ CUSTOM_TEMPLATES_DIRS.each do |template_dir|
71
+ if Dir.exists?(template_dir)
72
+ Dir["#{template_dir}/*"].each do |template|
73
+ puts "- #{File.basename(template)}\t(found at #{template_dir}/)"
74
+ end
75
+ end
76
+ end
77
+ end
78
+
79
+ def cat_template
80
+ default_template_dir = File.expand_path("templates/", File.dirname(__FILE__))
81
+ default_templates = Dir["#{default_template_dir}/*"]
82
+ template_name = default_templates.select { |path| File.basename(path) == @options['--name']}
83
+ puts File.open(template_name.first).read
84
+ rescue => e
85
+ puts "Could not fetch template '#{@options['--name']}'".red
86
+ end
87
+
88
+ def new_file
89
+ @org = OrgFile.new({ :title => @options["--title"],
90
+ :template => @options["<template>"],
91
+ :notebook => @options["<notebook>"] || @options["--notebook"],
92
+ :path => @options["--path"]
93
+ })
94
+ OrgFile.prepare_directories(@org)
95
+
96
+ c = 1
97
+ while File.exists?(@org[:file])
98
+ c += 1
99
+ @org[:filename] = Time.at(@org[:time]).strftime("%Y-%m-%d-%s-#{c}")
100
+ @org[:file] = File.expand_path(File.join(@org[:todo_dir], "#{@org[:filename]}.org"))
101
+ end
102
+ template = @org[:template] || 'writing'
103
+ template_file = find_template(template)
104
+ if not File.exists?(template_file)
105
+ puts "Could not find template `#{template}.org' at #{template_file}".red
106
+ exit 1
107
+ end
108
+ template = File.open(template_file).read
109
+ content = ERB.new(template).result(binding)
110
+ File.open(@org[:file], 'w') {|f| f.puts content }
111
+ puts content.yellow if ENV['DEBUG']
112
+ puts "Created a new writing at `#{@org[:file]}'".green
113
+ end
114
+
115
+ private
116
+ def find_template(template)
117
+ CUSTOM_TEMPLATES_DIRS.each do |template_dir|
118
+ if Dir.exists?(template_dir) and File.exists?(File.join(template_dir, "#{template}.org"))
119
+ return File.expand_path(File.join(template_dir, "#{template}.org"))
120
+ end
121
+ end
122
+
123
+ return File.expand_path(File.join('templates', "#{template}.org"), File.dirname(__FILE__))
124
+ end
125
+ end
126
+ end
@@ -0,0 +1,10 @@
1
+ module StringWithColors
2
+ def red; colorize("\e[0m\e[31m"); end
3
+ def green; colorize("\e[0m\e[32m"); end
4
+ def yellow; colorize("\e[0m\e[33m"); end
5
+ def bold; colorize("\e[0m\e[1m"); end
6
+ def colorize(color_code); "#{color_code}#{self}\e[0m"; end
7
+ end
8
+ class String
9
+ include StringWithColors
10
+ end
@@ -0,0 +1,78 @@
1
+ module ReOrg
2
+ class OrgFile
3
+
4
+ attr_accessor :options
5
+
6
+ DEFAULT_TODO_ORGS_DIR = 'todo'
7
+ DEFAULT_DONE_ORGS_DIR = 'done'
8
+
9
+ def initialize(opts={})
10
+ @options = opts
11
+ @options[:title] ||= 'Untitled'
12
+ @options[:time] = Time.now
13
+ @options[:date] = Time.at(@options[:time]).strftime("%Y-%m-%d")
14
+ @options[:org_format_date] = org_format_date(@options[:time])
15
+ @options[:todo_dir] ||= OrgFile.todo_dir
16
+ @options[:done_dir] ||= OrgFile.done_dir
17
+ @options[:notebook] ||= File.basename(File.expand_path('.'))
18
+ @options[:filename] = resolve_filename
19
+ @options[:file] = File.expand_path(File.join(@options[:todo_dir], "#{@options[:filename]}.org"))
20
+ end
21
+
22
+ def []=(key, value)
23
+ @options[key] = value
24
+ end
25
+
26
+ def [](key)
27
+ @options[key]
28
+ end
29
+
30
+ def org_format_date(time=nil)
31
+ time ||= @options[:time]
32
+ Time.at(time).strftime("[%Y-%m-%d %a]")
33
+ end
34
+
35
+ def resolve_filename
36
+ slug = slugify(@options[:title] || @options[:notebook])
37
+ Time.at(@options[:time]).strftime("%Y-%m-%d-#{slug}")
38
+ end
39
+
40
+ def slugify(name)
41
+ return nil unless name
42
+ name.gsub(/[\s.\/\\]/, '-').downcase
43
+ end
44
+
45
+ def self.prepare_directories(org={})
46
+ todo_dir = org[:path] || OrgFile.todo_dir
47
+ if not File.exists?(todo_dir)
48
+ puts "Creating working dir at `#{todo_dir}'".green
49
+ FileUtils.mkdir(todo_dir)
50
+ end
51
+ end
52
+
53
+ def self.path
54
+ File.expand_path(ENV['ORG_NOTEBOOKS_PATH'] || '.')
55
+ end
56
+
57
+ # FIXME: There should be a todo dir and a done dir?
58
+ def self.todo_dir
59
+ # Detect that we are on a Jekyll site and use _drafts
60
+ if File.exists?(File.expand_path('_config.yml', File.dirname('.'))) \
61
+ and Dir.exists?('_drafts')
62
+ File.expand_path('_drafts', File.dirname('.'))
63
+ else
64
+ File.expand_path("#{self.path}/#{DEFAULT_TODO_ORGS_DIR}", File.dirname('.'))
65
+ end
66
+ end
67
+
68
+ def self.done_dir
69
+ # Detect that we are on a Jekyll site and use _posts
70
+ if File.exists?(File.expand_path('_config.yml', File.dirname('.'))) \
71
+ and Dir.exists?('_posts')
72
+ File.expand_path('_posts', File.dirname('.'))
73
+ else
74
+ File.expand_path("#{self.path}/#{DEFAULT_DONE_ORGS_DIR}", File.dirname('.'))
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,14 @@
1
+ # -*- mode: org -*-
2
+ #+OPTIONS: ^:nil
3
+ #+TODO: TODO STARTED | DONE CANCELED
4
+ #+DATE: <%= @org[:date] %>
5
+ #+STARTUP: showeverything
6
+ #+NOTEBOOK: <%= @org[:notebook] %>
7
+
8
+ * [0/1] <%= @org[:org_format_date] %>
9
+ :PROPERTIES:
10
+ :DATE: <%= @org[:date] %>
11
+ :NOTEBOOK: <%= @org[:notebook] %>
12
+ :END:
13
+
14
+ ** TODO
@@ -0,0 +1,5 @@
1
+ #+title: <%= @org[:title].capitalize.gsub("-", " ") %>
2
+ #+date: <%= @org[:date] %>
3
+ #+layout: post
4
+ #+category: posts
5
+
@@ -0,0 +1,8 @@
1
+ # -*- mode: org -*-
2
+ #+OPTIONS: ^:nil
3
+ #+TITLE: <%= @org[:title] %>
4
+ #+DATE: <%= @org[:date] %>
5
+ #+STARTUP: showeverything
6
+ #+NOTEBOOK: <%= @org[:notebook] %>
7
+
8
+ <%= @org[:content] %>
@@ -0,0 +1,19 @@
1
+ # -*- mode: org -*-
2
+ #+OPTIONS: ^:nil
3
+ #+TITLE: <%= @org[:title] %>
4
+ #+DATE: <%= @org[:date] %>
5
+ #+STARTUP: showeverything
6
+ #+NOTEBOOK: <%= @org[:notebook] %>
7
+
8
+ *
9
+ :PROPERTIES:
10
+ :DATE: <%= @org[:date] %>
11
+ :NOTEBOOK: <%= @org[:notebook] %>
12
+ :END:
13
+
14
+
15
+ * COMMENT ________
16
+ # Local Variables:
17
+ # eval: (auto-fill-mode t)
18
+ # eval: (progn (goto-line 0)(re-search-forward ":PROPERTIES:") (org-narrow-to-subtree))
19
+ # End:
@@ -0,0 +1,3 @@
1
+ module ReOrg
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,20 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/re-org/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.authors = ["Waldemar Quevedo"]
6
+ gem.email = ["waldemar.quevedo@gmail.com"]
7
+ gem.description = %q{An Org mode file organizer}
8
+ gem.summary = %q{Instead of having tons of sparsed Org mode files everywhere, this project attemtps to give the Org mode writer a framework to re-organize the files in a less chaotic manner.
9
+ }
10
+ gem.homepage = "https://github.com/wallyqs/re-org"
11
+
12
+ gem.files = `git ls-files`.split($\)
13
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
14
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
15
+ gem.name = "re-org"
16
+ gem.require_paths = ["lib"]
17
+ gem.version = ReOrg::VERSION
18
+ gem.add_dependency(%q<docopt>)
19
+ gem.add_dependency(%q<org-ruby>)
20
+ end
@@ -0,0 +1,62 @@
1
+ require 'spec_helper'
2
+
3
+ describe ReOrg::Command do
4
+ before(:all) { $test_number = 0 }
5
+ before(:each) {
6
+ @dir = "#{RESULTS_DIR}/#{$test_number}"
7
+ FileUtils.mkdir_p(@dir)
8
+ ENV['ORG_NOTEBOOKS_PATH'] = @dir
9
+ }
10
+ after(:each) { $test_number += 1 }
11
+
12
+ context "when using `re-org new`" do
13
+ before(:each) do
14
+ @cmd = {
15
+ "new" => true,
16
+ "<template>" => 'writing',
17
+ "--notebook" => nil,
18
+ "--title" => "test-#{$test_number}",
19
+ }
20
+ end
21
+
22
+ it 'should create new writing for a notebook with --notebook option' do
23
+ @cmd['--notebook'] = 'tests'
24
+ o = ReOrg::Command.new(@cmd)
25
+ o.execute!
26
+ orgs = Dir["#{@dir}/todo/*"]
27
+ orgs.count.should == 1
28
+ end
29
+
30
+ it 'should create new clockfile when the template is choosen' do
31
+ @cmd['<template>'] = 'clockfile'
32
+ @cmd['--notebook'] = 'tests'
33
+ o = ReOrg::Command.new(@cmd)
34
+ o.execute!
35
+ orgs = Dir["#{@dir}/todo/*"]
36
+ orgs.count.should == 1
37
+ end
38
+
39
+ it 'should create new writing with --title option' do
40
+ @cmd['--notebook'] = 'tests'
41
+ @cmd['--title'] = 'Testing the title'
42
+ o = ReOrg::Command.new(@cmd)
43
+ o.execute!
44
+ orgs = Dir["#{@dir}/todo/*"]
45
+ orgs.count.should == 1
46
+ end
47
+ end
48
+
49
+ context "when using `re-org templates`" do
50
+ before(:each) do
51
+ @cmd = {
52
+ "templates" => true
53
+ }
54
+ end
55
+
56
+ it 'should display the currently installed templates' do
57
+ pending
58
+ o = ReOrg::Command.new(@cmd)
59
+ o.execute!
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,13 @@
1
+ require 'spec_helper'
2
+ require 'time'
3
+
4
+ describe ReOrg::OrgFile do
5
+ before(:each) do
6
+ @org = ReOrg::OrgFile.new
7
+ end
8
+
9
+ it 'should create date in org format' do
10
+ date = Time.at(1377411362)
11
+ @org.org_format_date(date).should == '[2013-08-25 Sun]'
12
+ end
13
+ end
@@ -0,0 +1,5 @@
1
+ require 're-org'
2
+ require 'fileutils'
3
+
4
+ RESULTS_DIR = File.expand_path("/tmp/#{Time.now.strftime("test_%s")}", File.dirname(__FILE__))
5
+ FileUtils.mkdir_p(RESULTS_DIR)
metadata ADDED
@@ -0,0 +1,93 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: re-org
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Waldemar Quevedo
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-12-08 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: docopt
16
+ requirement: &70292512920380 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *70292512920380
25
+ - !ruby/object:Gem::Dependency
26
+ name: org-ruby
27
+ requirement: &70292512916760 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: *70292512916760
36
+ description: An Org mode file organizer
37
+ email:
38
+ - waldemar.quevedo@gmail.com
39
+ executables:
40
+ - re-org
41
+ extensions: []
42
+ extra_rdoc_files: []
43
+ files:
44
+ - .gitignore
45
+ - Gemfile
46
+ - LICENSE
47
+ - README.org
48
+ - Rakefile
49
+ - TODO.org
50
+ - bin/re-org
51
+ - lib/re-org.rb
52
+ - lib/re-org/command.rb
53
+ - lib/re-org/ext.rb
54
+ - lib/re-org/org_file.rb
55
+ - lib/re-org/templates/clockfile.org
56
+ - lib/re-org/templates/jekyll-post.org
57
+ - lib/re-org/templates/notebook.org
58
+ - lib/re-org/templates/writing.org
59
+ - lib/re-org/version.rb
60
+ - re-org.gemspec
61
+ - spec/command_spec.rb
62
+ - spec/org_file_spec.rb
63
+ - spec/spec_helper.rb
64
+ homepage: https://github.com/wallyqs/re-org
65
+ licenses: []
66
+ post_install_message:
67
+ rdoc_options: []
68
+ require_paths:
69
+ - lib
70
+ required_ruby_version: !ruby/object:Gem::Requirement
71
+ none: false
72
+ requirements:
73
+ - - ! '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ required_rubygems_version: !ruby/object:Gem::Requirement
77
+ none: false
78
+ requirements:
79
+ - - ! '>='
80
+ - !ruby/object:Gem::Version
81
+ version: '0'
82
+ requirements: []
83
+ rubyforge_project:
84
+ rubygems_version: 1.8.10
85
+ signing_key:
86
+ specification_version: 3
87
+ summary: Instead of having tons of sparsed Org mode files everywhere, this project
88
+ attemtps to give the Org mode writer a framework to re-organize the files in a less
89
+ chaotic manner.
90
+ test_files:
91
+ - spec/command_spec.rb
92
+ - spec/org_file_spec.rb
93
+ - spec/spec_helper.rb