├── .gitignore ├── Gemfile ├── LICENSE.txt ├── README.md ├── Rakefile ├── bin └── rapp ├── lib ├── rapp.rb └── rapp │ ├── builder.rb │ ├── cli.rb │ ├── templates │ ├── Gemfile.erb │ ├── Rakefile.erb │ ├── app_name.rb.erb │ ├── config │ │ └── environments │ │ │ ├── development.rb.erb │ │ │ ├── production.rb.erb │ │ │ └── test.rb.erb │ ├── lib │ │ ├── app_name_base.rb.erb │ │ ├── env.rb.erb │ │ └── tasks │ │ │ ├── console.rake.erb │ │ │ └── environment.rake.erb │ └── spec │ │ ├── app_name_base │ │ └── env_spec.rb.erb │ │ ├── app_name_base_spec.rb.erb │ │ └── spec_helper.rb.erb │ └── version.rb └── rapp.gemspec /.gitignore: -------------------------------------------------------------------------------- 1 | /.bundle/ 2 | /.yardoc 3 | /Gemfile.lock 4 | /_yardoc/ 5 | /coverage/ 6 | /doc/ 7 | /pkg/ 8 | /spec/reports/ 9 | /tmp/ 10 | *.bundle 11 | *.so 12 | *.o 13 | *.a 14 | mkmf.log 15 | *.gem -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | # Specify your gem's dependencies in rapp.gemspec 4 | gemspec 5 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015 StabbyCutyou 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. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Rapp 2 | 3 | Rapp - The Ruby App Scaffolder 4 | 5 | ## Note 6 | 7 | Prior to this incarnation, there was an older, similar gem named Rapp which was abandoned. I have obtained the authors permission both for use of the name, as well as for use of the project on Ruby Gems. 8 | 9 | ## Installation 10 | 11 | Rapp is meant to run as a command line tool, not as a dependency. You should install it via the command line: 12 | 13 | ```shell 14 | $ gem install rapp 15 | ``` 16 | ## Usage 17 | 18 | Using Rapp is incredibly simple. It's designed to work like familiar scaffolders / builders in the ruby community (think `rails new`). 19 | 20 | Currently, Rapp is in early development, and additional features are forthcoming. There is a Roadmap at the bottom of the Readme to highlight some of the work I feel is important to prioritize before a full v1 release. In addition to features, this includes the internal organization of the code as well. 21 | 22 | ### Ethos 23 | 24 | Rapp is not a framework for running an app. In the future, there may be additional helpers to configure very common components in the ruby community, but the overall goal is to hand you a working application with a few common niceties, then get out of your way. Once you've generated the Rapp project, it is yours to do with as you see fit - the gem itself is not a dependency of the app you create. 25 | 26 | Rapp projects are shells to house your app, in a familiar layout, to prevent you from having to write the same boring boilerplate time and time again. 27 | 28 | Rapp is in no way shape or form meant for building web applications. You are free to attempt this if you wish, but if thats your goal, you're much better off with Rails, Sinatra, pure Rack, or any number of alternatives. 29 | 30 | ### Creating a new Rapp project 31 | 32 | Creating a new Rapp project is simple 33 | 34 | ```shell 35 | rapp my_new_rapp 36 | ``` 37 | 38 | The only requirement is that the directory must not exist as a safegaurd against accidentally overwriting any existing projects. Otherwise, thats it! 39 | 40 | If the command executed successfully, you should see a report displaying the folders and files that Rapp created for you. After that, you're ready to start building your app! 41 | 42 | ### Dependencies 43 | 44 | Rapp projects only have 2 dependencies - bundler and rake. Optionally, it will also include rspec, as well as a suite of specs for you to run to validate that the core underpinnings of the project are working as expected, in addition to your own custom specs. 45 | 46 | ### Layout 47 | 48 | Rapp project structure looks like the following: 49 | 50 | * app/ 51 | * app/models/ 52 | * app/services/ 53 | * app/jobs/ 54 | * bin/ 55 | * config/ 56 | * config/environments/ 57 | * config/initializers/ 58 | * lib/ 59 | * lib/tasks/ 60 | * spec/ (optional) 61 | * {app_name}.rb 62 | * {app_name}_base.rb 63 | * Gemfile 64 | * Rakefile 65 | 66 | ### {app_name}.rb 67 | 68 | This is the primary entry point for you application. It includes {app_name}_base to handle booting and requiring all the dependencies. The class itself is empty, and the only code that specifically resides in this file is adding the current directory to the load path, so it can more easily locate {app_name}_base. All other code for additions to the load path, requiring bundler dependencies, etc etc resides in {app_name}_base. 69 | 70 | ### {app_name}_base.rb 71 | 72 | Most of the generated code that Rapp creates lives here, such as: 73 | 74 | * Defining the environment 75 | * Providing an application level logger 76 | * Loading dependencies via Bundler 77 | * Adding core directories to the load path 78 | * Requiring configuration, initializers, and environment-specific settings 79 | * Requiring the contents of the app/ directory 80 | 81 | You're free to modify any of this code however you see fit - however, most of the code in your core app file is meant to be added to (and not removed) for the convenience of you, the developer. Be that as it may, you are still free to do whatever you want inside of this file. 82 | 83 | ### App directory 84 | 85 | This is likely a familiar concept to any Rails developer, with a few twists. Rails famously eschews the notion of keeping business logic in services - I do not eschew this practice, and believe it is the right way to keep a distinction between the logic of the application, and the data with which the application is modeled. You are free to use, ignore, remove, or otherwise throw out this directory as you see fit. 86 | 87 | Additionally, there is a directory for "jobs", a place for daemonized background or out of band work to go, to make working with things like Chore or Sidekiq easier out of the box. 88 | 89 | ### Bin directory 90 | 91 | If your application were to require an executable binary, it would be placed here. Otherwise, you may feel free to remove this directory 92 | 93 | ### Config directory 94 | 95 | Another familiar convention for Rails developers, this directory and it's structure is meant to work in the same fashion as Rails. Dependency specific configuration needs can be placed into config/, initializers for your apps boot-up can be placed into config/initializers/, and any code specific to an environment (production / development / test) can be placed into config/environments. The load order is as follows: 96 | 97 | 1. The correct environment.rb (defaults to development) 98 | 2. The contents of config/initializers/, in alphabetical order 99 | 3. The contents of config/, in alphabetical order 100 | 101 | These are loaded after Bundler, but before anything in app/ 102 | 103 | ### Lib directory 104 | 105 | Used for the same purpose as a Rails app or Ruby gem. Any code that falls outside of the norms of app/ would be placed here. Additionally, you may place tasks in lib/tasks/, and they will be registered via the Rake integration 106 | 107 | ### Rake 108 | 109 | Currently, Rapp comes with 2 predefined rake tasks: 110 | 111 | * console - This will boot up irb while loading your {app_name}.rb, which will load the rest of your app. This is aliased to "c" for convenience. 112 | * environment - This will load up the {app_name}.rb, which will load the rest of your app, for use in chaining custom rake tasks that will rely on your application code 113 | 114 | ### Specs (Optional) 115 | 116 | You can generate specs for your app to test the underpinnings of what Rapp has created. You can do this by specifying the ```--specs``` or ```-s``` flags on the command line. 117 | 118 | These specs aim to not be in the way of you writing your own specs, and so the spec_helper is sparse, and the generated specs attempt to not include a test for {app_name}, but rather {app_name}_base, so that you can do any {app_name} specific testing in that file yourself if you so choose. 119 | 120 | Mainly, these are here to help you make changes to a Rapp project once it's been generated if you so need, being able to verify that the core behaviors still function. 121 | 122 | ## Roadmap 123 | 124 | At the moment, this gem serves to fit a need that I found myself having and figured others might be as well. To that end, my main goals are to provide a simple, stable core ruby app intended to be run as a simple cli program, daemonized process, or otherwise. Currently, my primary roadmap for development is: 125 | 126 | 1. Generate increased / improved specs for the users application 127 | 2. General code cleanup. Much of the code is prototypical and is not as DRY as it could be (ex: the builder class) 128 | 3. Dotenv integration for ease of local development w/ sample file containing all env vars 129 | 4. Configurable logging level from the environment 130 | 5. Test ease of use integrating Chore / Sidekiq like job systems 131 | 132 | ## Contributing 133 | 134 | 1. Fork it ( https://github.com/StabbyCutyou/rapp/fork ) 135 | 2. Create your feature branch (`git checkout -b my-new-feature`) 136 | 3. Commit your changes (`git commit -am 'Add some feature'`) 137 | 4. Push to the branch (`git push origin my-new-feature`) 138 | 5. Create a new Pull Request 139 | 140 | # Contact 141 | 142 | Comments? Criticisms? Concerns? Open an issue on Github, or simply tweet at me. I'm @StabbyCutyou on Twitter. 143 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require "bundler/gem_tasks" 2 | 3 | -------------------------------------------------------------------------------- /bin/rapp: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib')) 3 | 4 | require 'rapp/builder' 5 | require 'rapp/cli' 6 | 7 | opts = Rapp::CLI.parse(ARGV) 8 | Rapp::Builder.new_app(opts) -------------------------------------------------------------------------------- /lib/rapp.rb: -------------------------------------------------------------------------------- 1 | require "rapp/version" 2 | 3 | module Rapp 4 | 5 | end 6 | -------------------------------------------------------------------------------- /lib/rapp/builder.rb: -------------------------------------------------------------------------------- 1 | require 'fileutils' 2 | require 'erb' 3 | require 'ostruct' 4 | require 'rapp/version' 5 | 6 | module Rapp 7 | DirectoryStructure = [ 8 | "app", 9 | "app/models", 10 | "app/services", 11 | "app/jobs", 12 | "bin", 13 | "config", 14 | "config/environments", 15 | "config/initializers", 16 | "lib", 17 | "lib/tasks", 18 | "log" 19 | ] 20 | 21 | SpecStructure = [ 22 | "spec", 23 | "spec/app_name_base" 24 | ] 25 | class Builder 26 | class << self 27 | def new_app(opts={}) 28 | # Get name 29 | raise ArgumentError.new("You must provide a name") unless app_name = opts[:name] 30 | # Check if folder exists 31 | root_dir = "#{Dir.pwd.strip}/#{app_name}" 32 | raise ArgumentError.new("Directory #{root_dir} already exists") if File.directory?(root_dir) 33 | 34 | # Build the directory structure first 35 | Dir.mkdir(root_dir) 36 | 37 | add_directories(DirectoryStructure, app_name, root_dir) 38 | 39 | # Construct the data object 40 | template_binding = OpenStruct.new( 41 | { :name=>app_name, 42 | :class_name=>classify(app_name), 43 | :rapp_version=>Rapp::VERSION 44 | }) 45 | 46 | # For each template, render it, place it in the folder structure it corresponds to 47 | # Skip spec dirs unless they said they wanted it 48 | # My intention here is to use "or" specifically, because it does not short-circuit. The second check is very important 49 | Dir["#{template_root}/**/*"].reject { |p| File.directory? p or p.include?('spec') }.each do |template| 50 | write_file(template, template_binding, app_name, root_dir) 51 | end 52 | 53 | # If set on the cli, build the spec stuff 54 | add_specs(root_dir, opts) if opts[:specs] 55 | 56 | puts "Finished creating #{app_name}" 57 | puts "#{`find ./#{app_name}`}" 58 | end 59 | 60 | def add_directories(directories, app_name, root_dir) 61 | directories.each do |dir| 62 | dir.gsub!('app_name', app_name) if dir.include?("app_name") 63 | dir_name = "#{root_dir}/#{dir}" 64 | FileUtils.mkdir_p(dir_name) unless File.directory?(dir_name) 65 | end 66 | end 67 | 68 | def write_file(template_name, template_binding, app_name, root_dir) 69 | template_data = File.read(template_name) 70 | relative_name = template_name.split("templates/")[1][0..-5] 71 | # Hack to make the entry point ruby file share the same name as the app 72 | relative_name.gsub!("app_name", app_name) 73 | 74 | result = ERB.new(template_data).result(template_binding.instance_eval {binding}) 75 | File.write("#{root_dir}/#{relative_name}", result) 76 | end 77 | 78 | def add_specs(root_dir, options) 79 | app_name = options[:name] 80 | #add rspec to the gemfile 81 | open("#{root_dir}/Gemfile", 'a') do |f| 82 | f.puts 'gem "rspec", "~>3.1.0"' 83 | end 84 | 85 | # Add the spec specific directories 86 | add_directories(SpecStructure, app_name, root_dir) 87 | 88 | # Construct the data object 89 | template_binding = OpenStruct.new( 90 | { :name=>app_name, 91 | :class_name=>classify(app_name), 92 | :rapp_version=>Rapp::VERSION 93 | }) 94 | 95 | # Get all the spec templates 96 | Dir["#{template_root}/spec/**/*"].reject {|p| File.directory? p }.each do |template| 97 | write_file(template, template_binding, app_name, root_dir) 98 | end 99 | end 100 | 101 | def classify(string) 102 | string.gsub(/(?<=_|^)(\w)/){$1.upcase}.gsub(/(?:_)(\w)/,'\1') 103 | end 104 | 105 | def template_root 106 | File.join(File.dirname(__FILE__), 'templates') 107 | end 108 | end 109 | end 110 | end 111 | -------------------------------------------------------------------------------- /lib/rapp/cli.rb: -------------------------------------------------------------------------------- 1 | require 'optparse' 2 | module Rapp 3 | class CLI 4 | class << self 5 | def parse(args) 6 | options = {:name=>args[0]} 7 | 8 | OptionParser.new do |opts| 9 | opts.banner = "Usage: rapp [app_name]" 10 | 11 | opts.on("-s", "--specs", "Generate basic validation specs for the app you build") do 12 | options[:specs] = true 13 | end 14 | end.parse! 15 | 16 | options 17 | end 18 | end 19 | end 20 | end -------------------------------------------------------------------------------- /lib/rapp/templates/Gemfile.erb: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gem "bundler", "~> 1.7" 4 | gem "rake", "~> 10.0" 5 | -------------------------------------------------------------------------------- /lib/rapp/templates/Rakefile.erb: -------------------------------------------------------------------------------- 1 | # Load project rake task files 2 | require 'bundler' 3 | Bundler.require(:default, ENV['APP_ENV'] || 'development') 4 | $: << File.expand_path("lib", File.dirname(__FILE__)) 5 | Dir["lib/tasks/*.rake"].each { |f| import f } -------------------------------------------------------------------------------- /lib/rapp/templates/app_name.rb.erb: -------------------------------------------------------------------------------- 1 | $:.unshift File.expand_path(".") 2 | $:.unshift File.expand_path("./lib") 3 | 4 | require '<%= app_name %>_base' 5 | class <%= class_name %> 6 | include <%=class_name%>Base 7 | 8 | end -------------------------------------------------------------------------------- /lib/rapp/templates/config/environments/development.rb.erb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StabbyCutyou/rapp/67be722e310d7e15b1d65e5b88029329230f5466/lib/rapp/templates/config/environments/development.rb.erb -------------------------------------------------------------------------------- /lib/rapp/templates/config/environments/production.rb.erb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StabbyCutyou/rapp/67be722e310d7e15b1d65e5b88029329230f5466/lib/rapp/templates/config/environments/production.rb.erb -------------------------------------------------------------------------------- /lib/rapp/templates/config/environments/test.rb.erb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StabbyCutyou/rapp/67be722e310d7e15b1d65e5b88029329230f5466/lib/rapp/templates/config/environments/test.rb.erb -------------------------------------------------------------------------------- /lib/rapp/templates/lib/app_name_base.rb.erb: -------------------------------------------------------------------------------- 1 | require 'env' 2 | require 'logger' 3 | 4 | module <%= class_name %>Base 5 | 6 | RAPP_VERSION="<%= rapp_version %>" 7 | 8 | def self.included(base) #:nodoc: 9 | base.extend(ClassMethods) 10 | <%= class_name%>Base.boot! 11 | end 12 | 13 | module ClassMethods 14 | def env 15 | @env ||= <%=class_name%>::Env.new(ENV['APP_ENV'] ||= 'development') 16 | end 17 | 18 | def root 19 | File.expand_path("..", File.dirname(__FILE__)) 20 | end 21 | 22 | def logger 23 | @logger ||= ::Logger.new(ENV['APP_LOG_PATH'] || "./log/<%= app_name %>.log").tap do |l| 24 | l.level = ::Logger::DEBUG 25 | l.formatter = lambda do |severity, datetime, progname, msg| 26 | "[#{datetime} (#{Process.pid})] #{severity} : #{msg}\n" 27 | end 28 | end 29 | end 30 | end 31 | 32 | def self.boot! 33 | # Load all dependent gems 34 | require 'bundler' 35 | Bundler.require(:default, <%=class_name %>.env.to_s) 36 | 37 | # Set up additional load paths 38 | 39 | # I'm not sure if we need "app" in the load path 40 | # Everything there should be auto-loaded, but you never know... 41 | $:.unshift File.expand_path("./app") 42 | 43 | # Load the right environment initializer 44 | 45 | require "config/environments/#{<%=class_name %>.env.to_s}" 46 | 47 | # Load initializers 48 | 49 | Dir["./config/initializers/*.rb"].sort.each {|file| require file } 50 | 51 | # Load config 52 | 53 | Dir["./config/**/*.rb"].sort.each {|file| require file} 54 | 55 | # Load job files 56 | 57 | Dir["./app/models/**/*.rb"].sort.each {|file| require file } 58 | Dir["./app/services/**/*.rb"].sort.each {|file| require file } 59 | Dir["./app/jobs/**/*.rb"].sort.each {|file| require file } 60 | end 61 | end 62 | -------------------------------------------------------------------------------- /lib/rapp/templates/lib/env.rb.erb: -------------------------------------------------------------------------------- 1 | class <%= class_name %> 2 | class Env 3 | def initialize(env) 4 | @env = env 5 | end 6 | 7 | def to_s 8 | @env.downcase 9 | end 10 | 11 | def production? 12 | @env == 'production' 13 | end 14 | 15 | def test? 16 | @end == 'test' 17 | end 18 | 19 | def development? 20 | @env == 'development' 21 | end 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /lib/rapp/templates/lib/tasks/console.rake.erb: -------------------------------------------------------------------------------- 1 | task :console do 2 | exec 'irb -r ./<%=name%>.rb' 3 | end 4 | 5 | task :c => :console -------------------------------------------------------------------------------- /lib/rapp/templates/lib/tasks/environment.rake.erb: -------------------------------------------------------------------------------- 1 | task :environment do 2 | require_relative '../../<%=app_name%>.rb' 3 | end -------------------------------------------------------------------------------- /lib/rapp/templates/spec/app_name_base/env_spec.rb.erb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe <%= class_name %>::Env do 4 | context 'when in production mode' do 5 | subject {<%= class_name%>::Env.new('production') } 6 | 7 | context '#production?' do 8 | it 'should be true' do 9 | expect(subject.production?).to eq(true) 10 | end 11 | end 12 | 13 | context '#development?' do 14 | it 'should be false' do 15 | expect(subject.development?).to eq(false) 16 | end 17 | end 18 | end 19 | 20 | context 'when in development mode' do 21 | subject {<%= class_name%>::Env.new('development') } 22 | 23 | context '#production?' do 24 | it 'should be true' do 25 | expect(subject.production?).to eq(false) 26 | end 27 | end 28 | 29 | context '#development?' do 30 | it 'should be false' do 31 | expect(subject.development?).to eq(true) 32 | end 33 | end 34 | end 35 | end -------------------------------------------------------------------------------- /lib/rapp/templates/spec/app_name_base_spec.rb.erb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe <%= class_name %>Base do 4 | context '#RAPP_VERSION' do 5 | it 'should be <%= rapp_version%>' do 6 | expect(subject::RAPP_VERSION).to eq("<%=rapp_version %>") 7 | end 8 | end 9 | 10 | context '#env' do 11 | before :each do 12 | # clear this before each run, restore to it's original value after. Kind of hacky, but dont wanna lose the app_env the user may have set 13 | @former_app_env = ENV['APP_ENV'] 14 | ENV['APP_ENV'] = nil 15 | 16 | # We also need to reset the env in the <%=class_name%> each time, so it tries to create a new Env object and picks up the new ENV value. Also kind of hacky 17 | <%= class_name%>.instance_variable_set('@env',nil) 18 | 19 | # These specs are made slightly more hacky to set up because I purposfully chose to have the Env be set once, and not make it automatically detect changes to APP_ENV. When the app boots up, it should detect it's environment once, and thats it. 20 | end 21 | 22 | after :each do 23 | ENV['APP_ENV'] = @former_app_env 24 | end 25 | 26 | context 'when no environment is specified' do 27 | it 'defaults to development' do 28 | expect(<%= class_name%>.env.to_s).to eq('development') 29 | end 30 | end 31 | 32 | it 'should get the configured environment from ENV' do 33 | ENV['APP_ENV'] = 'production' 34 | expect(<%= class_name%>.env.to_s).to eq('production') 35 | end 36 | end 37 | end -------------------------------------------------------------------------------- /lib/rapp/templates/spec/spec_helper.rb.erb: -------------------------------------------------------------------------------- 1 | $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..')) 2 | 3 | require 'rspec' 4 | require '<%= app_name %>' 5 | 6 | RSpec.configure do |config| 7 | 8 | end -------------------------------------------------------------------------------- /lib/rapp/version.rb: -------------------------------------------------------------------------------- 1 | module Rapp 2 | VERSION = "0.4.0" 3 | end 4 | -------------------------------------------------------------------------------- /rapp.gemspec: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | lib = File.expand_path('../lib', __FILE__) 3 | $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) 4 | require 'rapp/version' 5 | 6 | Gem::Specification.new do |spec| 7 | spec.name = "rapp" 8 | spec.version = Rapp::VERSION 9 | spec.authors = ["StabbyCutyou"] 10 | spec.email = ["sean.kelly@tapjoy.com"] 11 | spec.summary = %q{rapp - A gem for building Ruby Apps} 12 | spec.description = %q{rapp helps you build native ruby apps with a familiar structure and a handful of familiar conventions.} 13 | spec.homepage = "https://github.com/StabbyCutyou/rapp" 14 | spec.license = "MIT" 15 | 16 | spec.files = `git ls-files -z`.split("\x0") 17 | spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) } 18 | spec.test_files = spec.files.grep(%r{^(test|spec|features)/}) 19 | spec.require_paths = ["lib"] 20 | 21 | spec.add_development_dependency "bundler", "~> 1.7" 22 | spec.add_development_dependency "rake", "~> 10.0" 23 | spec.add_development_dependency "rspec", "~> 3.1.0" 24 | end 25 | --------------------------------------------------------------------------------