doubleshot 0.1.0-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. data/Doubleshot +33 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.textile +208 -0
  4. data/bin/doubleshot +7 -0
  5. data/ext/java/Empty.java +0 -0
  6. data/lib/doubleshot.rb +37 -0
  7. data/lib/doubleshot/cli.rb +84 -0
  8. data/lib/doubleshot/cli/options.rb +34 -0
  9. data/lib/doubleshot/commands/build.rb +34 -0
  10. data/lib/doubleshot/commands/gem.rb +39 -0
  11. data/lib/doubleshot/commands/init.rb +129 -0
  12. data/lib/doubleshot/commands/install.rb +35 -0
  13. data/lib/doubleshot/commands/jar.rb +7 -0
  14. data/lib/doubleshot/commands/test.rb +119 -0
  15. data/lib/doubleshot/compiler.rb +47 -0
  16. data/lib/doubleshot/configuration.rb +361 -0
  17. data/lib/doubleshot/configuration/source_locations.rb +59 -0
  18. data/lib/doubleshot/dependencies.rb +31 -0
  19. data/lib/doubleshot/dependencies/dependency.rb +38 -0
  20. data/lib/doubleshot/dependencies/dependency_list.rb +60 -0
  21. data/lib/doubleshot/dependencies/gem_dependency.rb +8 -0
  22. data/lib/doubleshot/dependencies/gem_dependency_list.rb +10 -0
  23. data/lib/doubleshot/dependencies/jar_dependency.rb +8 -0
  24. data/lib/doubleshot/dependencies/jar_dependency_list.rb +10 -0
  25. data/lib/doubleshot/jar.rb +51 -0
  26. data/lib/doubleshot/readonly_collection.rb +32 -0
  27. data/lib/doubleshot/setup.rb +49 -0
  28. data/lib/ruby/blank.rb +132 -0
  29. data/lib/ruby/gem/requirement.rb +5 -0
  30. data/lib/ruby/kernel.rb +8 -0
  31. data/lib/ruby/pathname.rb +11 -0
  32. data/lib/ruby/string.rb +42 -0
  33. data/lib/ruby/time.rb +8 -0
  34. data/test/compiler_spec.rb +44 -0
  35. data/test/configuration/source_locations_spec.rb +98 -0
  36. data/test/configuration_spec.rb +295 -0
  37. data/test/dependencies/dependency_list_spec.rb +73 -0
  38. data/test/dependencies/dependency_spec.rb +49 -0
  39. data/test/dependencies/gem_dependency_list_spec.rb +7 -0
  40. data/test/dependencies/gem_dependency_spec.rb +7 -0
  41. data/test/dependencies/jar_dependency_list_spec.rb +7 -0
  42. data/test/dependencies/jar_dependency_spec.rb +7 -0
  43. data/test/dependencies_spec.rb +42 -0
  44. data/test/doubleshot_spec.rb +51 -0
  45. data/test/helper.rb +18 -0
  46. data/test/readonly_collection_spec.rb +45 -0
  47. metadata +300 -0
data/Doubleshot ADDED
@@ -0,0 +1,33 @@
1
+ # encoding: UTF-8
2
+
3
+ Doubleshot.new do |config|
4
+
5
+ config.gem "bundler", ">= 0"
6
+ config.gem "jbundler", ">= 0"
7
+
8
+ config.gem "rdoc", ">= 2.4.2"
9
+ config.gem "perfer", ">= 0"
10
+ config.gem "minitest", ">= 3.0.1"
11
+ config.gem "minitest-wscolor", ">= 0"
12
+ config.gem "listen", ">= 0"
13
+ config.gem "rb-fsevent", "~> 0.9.1"
14
+ config.gem "simplecov", ">= 0"
15
+
16
+ config.gemspec do |spec|
17
+ spec.name = "doubleshot"
18
+ spec.version = "0.1.0"
19
+ spec.summary = "Doubleshot is a build and dependency tool for mixed Java and Ruby projects"
20
+ spec.description = <<-DESCRIPTION
21
+ Doubleshot will download dependencies on demand, compile your Java sources and
22
+ let you spend most of your time in Ruby without having to juggle two different
23
+ dependency management tools, different build tools and being forced to execute
24
+ your code through Rake or Maven based tools.
25
+ DESCRIPTION
26
+ spec.homepage = "https://github.com/sam/doubleshot"
27
+ spec.author = "Sam Smoot"
28
+ spec.email = "ssmoot@gmail.com"
29
+ spec.license = "MIT-LICENSE"
30
+ spec.executables = ["doubleshot"]
31
+ end
32
+
33
+ end
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2012 Sam Smoot
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.textile ADDED
@@ -0,0 +1,208 @@
1
+ h1. Doubleshot
2
+
3
+ Latest test results (currently Travis CI's JRuby ~1.7 mode is broken as it runs `bundle install` but doesn't have the Bundler gem installed):
4
+
5
+ !https://secure.travis-ci.org/sam/doubleshot.png(Build Status)!:http://travis-ci.org/sam/doubleshot
6
+
7
+ Doubleshot aims to let you write Java, and Ruby in the same project, and streamline the dependency, testing and build process.
8
+
9
+ You can have dependencies on both Gems and JARs, and easily package it all up in a redistributable Gem or Unified JAR when you're ready to ship.
10
+
11
+ When you clone a Doubleshot project, you can run it just like any other Ruby script. There's no external tool you have to call. There's no setup or installation process for dependencies. That all happens on-demand. You only need to use the provided @doubleshot@ command if you want to run the (optional) testing sandbox, or prepare a package for release. If you'd rather directly execute your test files, use a @RakeTestTask@, or whatever, you're free to do that.
12
+
13
+ Happy coding!
14
+
15
+ * "Overview":#overview
16
+ * "Usage":#usage
17
+ ** "Requirements":#requirements
18
+ ** "Installation":#installation
19
+ ** "Project Layout":#project-layout
20
+ ** "Testing":#testing-two-ways
21
+ *** "Direct Execution":#direct-execution
22
+ *** "Sandbox Execution":#sandbox-execution
23
+ ** "Packaging":#packaging
24
+ * "Tips":#tips
25
+ ** "Nailgun Usage":#use-doubleshot-with-nailgun-for-great-success
26
+ * "FAQ":#faq
27
+
28
+ h2. Overview
29
+
30
+ *JRuby is amazing.*
31
+
32
+ Unfortunately there's no simple standard way to create a Ruby Gem that contains both Java and Ruby sources, with both JAR and Gem dependencies.
33
+
34
+ Before Doubleshot you'd probably use "Bundler":https://github.com/carlhuda/bundler to manage your Gem dependencies, "JBundler":https://github.com/mkristian/jbundler to manage your JAR dependencies and "Buildr":https://github.com/apache/buildr (which is built on top of Rake) to compile and package your project. That's _really_ cumbersome. Especially since Buildr wasn't built for this, (it's focus is _Java_ projects, as a substitute for Maven) and there really is very little documentation on how to accomplish your goals.
35
+
36
+ On top of that, you're now forced to run Rake and load these massive libraries even just to execute a single @TestCase@. And you'll have to run it every time. If you're a fan of TDD, you can realistically spend a substantial portion of your day just waiting for the JVM to load Maven, Bundler and Rake. Over. And Over. And Over.
37
+
38
+ It's *painful* is what it is.
39
+
40
+ You have a JRuby project with both Java and Ruby source files. You need to:
41
+
42
+ * Compile your Java
43
+ * Download JAR dependencies from a "Maven repository":http://mvnrepository.com/
44
+ * Download Gem dependencies from a "Rubygems server":https://github.com/sam/geminaboxplus
45
+ * Java Classes and Dependencies should be added to the @$CLASSPATH@ at runtime
46
+ * Write your tests in a single language (Ruby) using "Minitest":https://github.com/seattlerb/minitest
47
+ * Execute your Ruby normally, without the need for wrappers like Rake or @bundle exec@
48
+ * Automatically compile and reload Java sources on update, then execute the appropriate tests
49
+ * Reload your testing sandbox after updating Ruby sources without side-effects from previous versions code
50
+ * Package your mixed-language project and it's JAR dependencies into a Gem you can release
51
+ * Package a project and all it's dependencies up as a JAR so all you need on your server is Java
52
+
53
+ Here's what tools Doubleshot replaces in your workflow:
54
+
55
+ * Bundler
56
+ * JBundler
57
+ * GemPackageTask
58
+ * RakeTestTask
59
+ * Maven Dependencies
60
+ * Maven Assemblies
61
+ * Build tools like Ant or Buildr
62
+
63
+ h1. Usage
64
+
65
+ h2. Requirements
66
+
67
+ * Java 6 or later
68
+ * Maven
69
+ * JRuby 1.7 or later
70
+ * Ruby 1.9 syntax only
71
+
72
+ h2. Installation
73
+
74
+ bc. gem install doubleshot
75
+
76
+ h2. Project Layout
77
+
78
+ The *default* project using Doubleshot as it's build-tool will have the following layout:
79
+
80
+ bc.. ext/
81
+ java/
82
+ Hello.java # Java sources appear under the ext/java folder.
83
+ lib/
84
+ world.rb # Ruby sources go in the standard location.
85
+ test/
86
+ helper.rb
87
+ hello_spec.rb # specs match up to lib/**/*.rb or ext/java/**/*.java
88
+ world_spec.rb
89
+ Doubleshot # Your Doubleshot file replaces your project's gemspec
90
+ # and JBundler's Jarfile.
91
+
92
+ p. Your tests should be executable and look something like this:
93
+
94
+ bc.. #!/usr/local/env jruby
95
+
96
+ require_relative "helper.rb"
97
+
98
+ java_import org.sam.doubleshot.example.Hello
99
+
100
+ describe Hello do
101
+ it "must rock you" do
102
+ Hello.rock(:you).must_equal true
103
+ end
104
+ end
105
+
106
+ p. ...and @helper.rb@ would look something like this:
107
+
108
+ bc.. require "doubleshot"
109
+ require "minitest/autorun"
110
+
111
+ h2. Testing Two Ways
112
+
113
+ h3. Direct Execution
114
+
115
+ p. Now you can execute your spec file directly and Doubleshot will:
116
+
117
+ # Ensure that the dependencies defined in the @Doubleshot@ file are met by resolving their versions, downloading them, and adding them to your environment.
118
+ # Compile any code found in @ext/java@ that's not already compiled.
119
+
120
+ Then Minitest will run your test and exit when it's done.
121
+
122
+ h3. Sandbox Execution
123
+
124
+ Doubleshot also provides a @doubleshot@ bin file. Running @doubleshot test@ in your project's home directory will setup monitors for @lib/@ and @test/@ and wait for changes, applying the rules below to it's execution:
125
+
126
+ * When source under @ext/java/@ changes, it will be recompiled, reloaded, and matching tests searched for to execute
127
+ * When Ruby source under @lib/@ changes, your Ruby VM will be reloaded, and matching tests executed
128
+ * If any tests change, the sandbox will be reloaded (since tests are written in Ruby), and the test file executed
129
+ * If a @SIGINT@ (@^C@) is received, all tests will be loaded and executed
130
+ * If a second @SIGINT@ is received before execution of the full test-suite is finished, the monitor will exit cleanly
131
+
132
+ This is the typical use-case for day to day development of new projects/features when using Doubleshot to manage your build process. It allows you to write and test new code, without ever having to restart your Java VM, saving you ten seconds or so for every run, encouraging continuous testing so you can spend more time writing code, and less time waiting for processes to load.
133
+
134
+ h2. Packaging
135
+
136
+ # TODO: This is all out of date...
137
+
138
+ Given a project named _Example_, then @example.gemspec@ would include your Gem dependencies (including "doubleshot") and your @Doubleshot@ file would include your JAR dependencies as well as pulling in your Gem dependencies from your gemspec. This way your project is backwards compatible with Rubygems and Bundler. When packaging your project, your JAR dependencies will be "vendored" into the gem you've built.
139
+
140
+ Within your project (ie: @lib/example.rb@) you'll @require "doubleshot"@. This will ensure any dependencies for your Gem are satisfied at runtime. If a dependency is already loaded, (an upstream project called @require "bundler/setup"@ for example) then Doubleshot will skip it.
141
+
142
+ If you're running inside of a @doubleshot/setup@ then requiring @doublehsot/setup@ will have no effect to avoid doubling up on the work.
143
+
144
+ To build a gem, run the @doubleshot build@ command on the command line. Doubleshot will ensure all dependencies are satisfied, compile your code, vendor any JAR dependencies and finally create a gem for you based on your @example.gemspec@ file.
145
+
146
+ If you want your build to be conditional upon passing tests, add the @test :minitest@ directive to your @Doubleshot@ file. If you need to temporarily skip the tests to build a gem with this option enabled, use @NOTEST=true doubleshot build@ to package your gem.
147
+
148
+ h1. Tips
149
+
150
+ h2. Use Doubleshot with Nailgun for Great Success!
151
+
152
+ Open a terminal window and navigate to the root of your project (to make sure you're using the right JRuby if you have an @.rvmrc@). Then run:
153
+
154
+ bc. jruby --ng-server &
155
+
156
+ Now run your code (any JRuby code, not just Doubleshot) as usual, but add the @--ng@ option to JRuby:
157
+
158
+ bc. jruby --ng -r lib/doubleshot/setup.rb -e "puts org.foo.Bar.baz"
159
+
160
+ It may take a few cycles while things warm up, but you should see this cut your process load-time by several seconds. It's especially handy if you're running lots of test cases directly as detailed in the first testing scenario. It could easily cut your testing time in half (or more).
161
+
162
+ When you're done for the day, just foreground the server with the @fg@ command, and @SIGINT@ it (@^C@) to quit.
163
+
164
+ h1. FAQ
165
+
166
+ h2. What's in a Name?
167
+
168
+ A shot each of JRuby and Java. Doubleshot.
169
+
170
+ h2. Where is @doubleshot show@?
171
+
172
+ Bundler includes a @bundle show some_gem@ command that shows you the path where a dependency was unpacked after running @bundle install@. I've only ever used that in two cases:
173
+
174
+ *View the source of some library to try to trace a bug:* Write a test to trace your bug. View the source online or clone it and view it locally. It's a minor inconvenience sure, but it's a lot less prone to abuse.
175
+
176
+ *Hack in a quick "hot-fix" for a production issue:* You shouldn't be making changes outside of source-control. That's an obvious development anti-pattern.
177
+
178
+ It's our opinion that you don't _need_ this functionality, and it opens the window to abuse, so we're not implementing it.
179
+
180
+ h2. Where is @doubleshot install@?
181
+
182
+ With Bundler it's common to:
183
+
184
+ # @bundle install@ to inspect your Gemfile and download/install any missing dependencies
185
+ # @require "bundler/setup"@ to check/require dependencies at runtime
186
+
187
+ With Doubleshot you'll:
188
+
189
+ bc. require "doubleshot/setup"
190
+
191
+ Doubleshot will first see if all it's dependencies are available, and if not, install any that are missing. So you don't have to manually run an installation step.
192
+
193
+ bq.. But I just want to install my Gem dependencies on a remote server and not actually attempt to run any code!
194
+ *-- Said No One Ever*
195
+
196
+ p. If you _really_ want to pre-download your dependencies just run @jruby -r "doubleshot/setup"@ in your project's home-directory. Nothing to it.
197
+
198
+ h2. What if I want to create a unified JAR containing all my dependencies?
199
+
200
+ Use @doubleshot jar [main-class]@. By default the main-class will use JRuby's bootstrapping mechanism @org.jruby.JarBootstrapMain@, where you add your own @jar-bootstrap.rb@ file to be required.
201
+
202
+ All gems will be unpacked and copied in. All JAR dependencies will be copied in as well.
203
+
204
+ This will leave you with an @example.jar@ you can just copy up to a server, and as long as a compatible version of Java is installed (typically Java6 or later), you have everything you need to run your application bundled in. Now you just need to run @java -jar example.jar@ and you're off to the races!
205
+
206
+ h2. Does Doubleshot support Ruby 1.8.x syntax?
207
+
208
+ No.
data/bin/doubleshot ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env jruby
2
+
3
+ require "pathname"
4
+ require Pathname(__FILE__).dirname.parent + "lib/doubleshot"
5
+ require Pathname(__FILE__).dirname.parent + "lib/doubleshot/cli"
6
+
7
+ exit Doubleshot::CLI::start ? 0 : 1
File without changes
data/lib/doubleshot.rb ADDED
@@ -0,0 +1,37 @@
1
+ require "pathname"
2
+ require "set"
3
+
4
+ $:.unshift(Pathname(__FILE__).dirname)
5
+
6
+ require "ruby/gem/requirement"
7
+ require "ruby/string"
8
+ require "ruby/blank"
9
+ require "ruby/pathname"
10
+ require "ruby/kernel"
11
+ require "ruby/time"
12
+ require "doubleshot/readonly_collection"
13
+ require "doubleshot/configuration"
14
+ require "doubleshot/compiler"
15
+
16
+ class Doubleshot
17
+ def initialize(&b)
18
+ @config = Doubleshot::Configuration.new
19
+ yield @config
20
+ end
21
+
22
+ def build_gemspec
23
+ @config.gemspec.to_ruby
24
+ end
25
+
26
+ def config
27
+ @config
28
+ end
29
+
30
+ def self.current
31
+ @current ||= load
32
+ end
33
+
34
+ def self.load
35
+ eval(Pathname("Doubleshot").read)
36
+ end
37
+ end
@@ -0,0 +1,84 @@
1
+ require_relative "../doubleshot"
2
+ require "doubleshot/cli/options"
3
+
4
+ class Doubleshot
5
+ class CLI
6
+
7
+ module Commands
8
+ end
9
+
10
+ class << self
11
+ public :binding
12
+ end
13
+
14
+ def self.commands
15
+ @commands ||= []
16
+ end
17
+
18
+ def self.inherited(target)
19
+ commands << target
20
+ end
21
+
22
+ def self.task_name
23
+ name.split("::").last.underscore
24
+ end
25
+
26
+ def self.summary
27
+ raise NotImplementedError.new
28
+ end
29
+
30
+ def self.options
31
+ raise NotImplementedError.new
32
+ end
33
+
34
+ def self.start(args)
35
+ raise NotImplementedError.new
36
+ end
37
+
38
+ USAGE = <<-EOS.margin
39
+ Usage: doubleshot COMMAND [ OPTIONS ]
40
+
41
+ Summary: Command line tool for creating and managing doubleshot projects.
42
+
43
+ EOS
44
+
45
+ def self.usage(command_name = "")
46
+ if command_name.blank?
47
+ puts USAGE
48
+
49
+ commands.each do |command|
50
+ puts("\n doubleshot %-8s # %s" % [ command.task_name, command.summary.gsub("\n", "\n" + (" " * 22) + "# ") ])
51
+ end
52
+ elsif command = detect(command_name)
53
+ puts command.options
54
+ else
55
+ puts "\nERROR! COMMAND NOT FOUND: #{command_name}\n\n"
56
+ usage
57
+ exit 1
58
+ end
59
+ exit 0
60
+ end
61
+
62
+ def self.detect(command_name)
63
+ commands.detect { |command| command.task_name == command_name }
64
+ end
65
+
66
+ def self.start
67
+ if ARGV[0] == "help"
68
+ usage(ARGV[1])
69
+ elsif command = commands.detect { |command| command.task_name == ARGV[0] }
70
+ command.start(ARGV[1..-1])
71
+ else
72
+ usage(ARGV[0])
73
+ end
74
+ end
75
+
76
+ end # class CLI
77
+ end # class Doubleshot
78
+
79
+ require_relative "commands/init"
80
+ require_relative "commands/test"
81
+ require_relative "commands/build"
82
+ require_relative "commands/gem"
83
+ require_relative "commands/jar"
84
+ require_relative "commands/install"
@@ -0,0 +1,34 @@
1
+ require "optparse"
2
+ require "ostruct"
3
+
4
+ class Doubleshot
5
+ class CLI
6
+ class Options < OpenStruct
7
+
8
+ def self.__forward__(*methods)
9
+ methods.each do |method|
10
+ define_method(method) do |*args, &b|
11
+ @parser.send(method, *args, &b)
12
+ end
13
+ end
14
+ end
15
+
16
+ __forward__ :banner, :separator, :on
17
+
18
+ def initialize
19
+ super
20
+ @parser = OptionParser.new
21
+ yield self
22
+ end
23
+
24
+ def parse!(args)
25
+ self.args = @parser.parse! args
26
+ self
27
+ end
28
+
29
+ def to_s
30
+ @parser.to_s
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,34 @@
1
+ class Doubleshot::CLI::Commands::Build < Doubleshot::CLI
2
+ def self.summary
3
+ <<-EOS.margin
4
+ Download all dependencies and compile sources so that you
5
+ can use the project directly without installation, such
6
+ as with IRB.
7
+
8
+ NOTE: Packaging and testing have a dependency on this
9
+ command. You don't need to build as a prerequisite.
10
+ EOS
11
+ end
12
+
13
+ def self.options
14
+ Options.new do |options|
15
+ options.banner = "Usage: doubleshot build"
16
+
17
+ options.separator ""
18
+ options.separator "Summary: #{summary}"
19
+ end
20
+ end
21
+
22
+ def self.start(args)
23
+ config = Doubleshot::current.config
24
+
25
+ # TODO:
26
+ # download JAR dependencies
27
+ # setup correct class-path
28
+ # download Gem dependencies
29
+ # compile Java
30
+ # exit
31
+
32
+ return true
33
+ end
34
+ end