├── LICENSE ├── README.txt ├── Rakefile ├── cloby.gemspec ├── examples └── simple.rb ├── javalib └── clojure-1.2.0.jar ├── lib ├── cloby.rb └── cloby_ext.jar └── src └── org └── jruby └── clojure └── ClojureLibrary.java /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | 3 | Version 2.0, January 2004 4 | 5 | http://www.apache.org/licenses/ 6 | 7 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 8 | 9 | 1. Definitions. 10 | 11 | "License" shall mean the terms and conditions for use, reproduction, and distribution as 12 | defined by Sections 1 through 9 of this document. 13 | 14 | "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that 15 | is granting the License. 16 | 17 | "Legal Entity" shall mean the union of the acting entity and all other entities that 18 | control, are controlled by, or are under common control with that entity. For the purposes 19 | of this definition, "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or otherwise, or (ii) ownership 21 | of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of 22 | such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by 25 | this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, including but not 28 | limited to software source code, documentation source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical transformation or translation of 31 | a Source form, including but not limited to compiled object code, generated documentation, 32 | and conversions to other media types. 33 | 34 | "Work" shall mean the work of authorship, whether in Source or Object form, made available 35 | under the License, as indicated by a copyright notice that is included in or attached to the 36 | work (an example is provided in the Appendix below). 37 | 38 | "Derivative Works" shall mean any work, whether in Source or Object form, that is based on 39 | (or derived from) the Work and for which the editorial revisions, annotations, elaborations, 40 | or other modifications represent, as a whole, an original work of authorship. For the 41 | purposes of this License, Derivative Works shall not include works that remain separable 42 | from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works 43 | thereof. 44 | 45 | "Contribution" shall mean any work of authorship, including the original version of the Work 46 | and any modifications or additions to that Work or Derivative Works thereof, that is 47 | intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by 48 | an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the 49 | purposes of this definition, "submitted" means any form of electronic, verbal, or written 50 | communication sent to the Licensor or its representatives, including but not limited to 51 | communication on electronic mailing lists, source code control systems, and issue tracking 52 | systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and 53 | improving the Work, but excluding communication that is conspicuously marked or otherwise 54 | designated in writing by the copyright owner as "Not a Contribution." 55 | 56 | "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a 57 | Contribution has been received by Licensor and subsequently incorporated within the Work. 58 | 59 | 2. Grant of Copyright License. Subject to the terms and conditions of this License, each 60 | Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, 61 | royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, 62 | publicly display, publicly perform, sublicense, and distribute the Work and such Derivative 63 | Works in Source or Object form. 64 | 65 | 3. Grant of Patent License. Subject to the terms and conditions of this License, each 66 | Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, 67 | royalty-free, irrevocable (except as stated in this section) patent license to make, have 68 | made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license 69 | applies only to those patent claims licensable by such Contributor that are necessarily 70 | infringed by their Contribution(s) alone or by combination of their Contribution(s) with the 71 | Work to which such Contribution(s) was submitted. If You institute patent litigation against 72 | any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or 73 | a Contribution incorporated within the Work constitutes direct or contributory patent 74 | infringement, then any patent licenses granted to You under this License for that Work shall 75 | terminate as of the date such litigation is filed. 76 | 77 | 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works 78 | thereof in any medium, with or without modifications, and in Source or Object form, provided 79 | that You meet the following conditions: 80 | 81 | You must give any other recipients of the Work or Derivative Works a copy of this License; 82 | and 83 | 84 | You must cause any modified files to carry prominent notices stating that You changed the 85 | files; and 86 | 87 | You must retain, in the Source form of any Derivative Works that You distribute, all 88 | copyright, patent, trademark, and attribution notices from the Source form of the Work, 89 | excluding those notices that do not pertain to any part of the Derivative Works; and 90 | 91 | If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative 92 | Works that You distribute must include a readable copy of the attribution notices contained 93 | within such NOTICE file, excluding those notices that do not pertain to any part of the 94 | Derivative Works, in at least one of the following places: within a NOTICE text file 95 | distributed as part of the Derivative Works; within the Source form or documentation, if 96 | provided along with the Derivative Works; or, within a display generated by the Derivative 97 | Works, if and wherever such third-party notices normally appear. The contents of the NOTICE 98 | file are for informational purposes only and do not modify the License. You may add Your own 99 | attribution notices within Derivative Works that You distribute, alongside or as an addendum 100 | to the NOTICE text from the Work, provided that such additional attribution notices cannot 101 | be construed as modifying the License. You may add Your own copyright statement to Your 102 | modifications and may provide additional or different license terms and conditions for use, 103 | reproduction, or distribution of Your modifications, or for any such Derivative Works as a 104 | whole, provided Your use, reproduction, and distribution of the Work otherwise complies with 105 | the conditions stated in this License. 106 | 107 | 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution 108 | intentionally submitted for inclusion in the Work by You to the Licensor shall be under the 109 | terms and conditions of this License, without any additional terms or conditions. 110 | Notwithstanding the above, nothing herein shall supersede or modify the terms of any 111 | separate license agreement you may have executed with Licensor regarding such Contributions. 112 | 113 | 6. Trademarks. This License does not grant permission to use the trade names, trademarks, 114 | service marks, or product names of the Licensor, except as required for reasonable and 115 | customary use in describing the origin of the Work and reproducing the content of the NOTICE 116 | file. 117 | 118 | 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, 119 | Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" 120 | BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, 121 | without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, 122 | MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for 123 | determining the appropriateness of using or redistributing the Work and assume any risks 124 | associated with Your exercise of permissions under this License. 125 | 126 | 8. Limitation of Liability. In no event and under no legal theory, whether in tort 127 | (including negligence), contract, or otherwise, unless required by applicable law (such as 128 | deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be 129 | liable to You for damages, including any direct, indirect, special, incidental, or 130 | consequential damages of any character arising as a result of this License or out of the use 131 | or inability to use the Work (including but not limited to damages for loss of goodwill, 132 | work stoppage, computer failure or malfunction, or any and all other commercial damages or 133 | losses), even if such Contributor has been advised of the possibility of such damages. 134 | 135 | 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative 136 | Works thereof, You may choose to offer, and charge a fee for, acceptance of support, 137 | warranty, indemnity, or other liability obligations and/or rights consistent with this 138 | License. However, in accepting such obligations, You may act only on Your own behalf and on 139 | Your sole responsibility, not on behalf of any other Contributor, and only if You agree to 140 | indemnify, defend, and hold each Contributor harmless for any liability incurred by, or 141 | claims asserted against, such Contributor by reason of your accepting any such warranty or 142 | additional liability. 143 | 144 | END OF TERMS AND CONDITIONS 145 | -------------------------------------------------------------------------------- /README.txt: -------------------------------------------------------------------------------- 1 | Usage: 2 | 3 | 1. Install the gem 4 | 2. Extend Clojure::Object 5 | 6 | A top-level method called dosync will be defined that takes a block of code, and your class will have transactional semantics for its instance variables. 7 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require 'ant' 2 | 3 | directory "pkg/classes" 4 | 5 | desc "Clean up build artifacts" 6 | task :clean do 7 | rm_rf "pkg/classes" 8 | rm_rf "lib/cloby_ext.jar" 9 | end 10 | 11 | desc "Compile the extension" 12 | task :compile => "pkg/classes" do |t| 13 | ant.javac :srcdir => "src", :destdir => t.prerequisites.first, 14 | :source => "1.5", :target => "1.5", :debug => true, 15 | :classpath => "${java.class.path}:${sun.boot.class.path}:lib/clojure-1.2.0.jar" 16 | end 17 | 18 | desc "Build the jar" 19 | task :jar => :compile do 20 | ant.jar :basedir => "pkg/classes", :destfile => "javalib/cloby_ext.jar", :includes => "**/*.class" 21 | end 22 | 23 | task :package => :jar 24 | 25 | desc "Run the specs" 26 | task :spec => :jar do 27 | ruby "-S", "spec", "spec" 28 | end 29 | -------------------------------------------------------------------------------- /cloby.gemspec: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | Gem::Specification.new do |s| 4 | s.name = %q{cloby} 5 | s.version = "0.0.3" 6 | s.authors = ["Charles Oliver Nutter"] 7 | s.date = Time.now 8 | s.description = "Clojure-based transactional semantics for Ruby instance variables" 9 | s.email = ["headius@headius.com"] 10 | s.files = Dir['{lib,examples,test}/**/*'] + Dir['{*.txt,*.gemspec,Rakefile}'] 11 | s.homepage = "http://github.com/headius/cloby" 12 | s.require_paths = ["lib"] 13 | s.summary = "Clojure-based transactional semantics for Ruby instance variables" 14 | s.test_files = Dir["spec/*_spec.rb"] 15 | s.platform = "java" 16 | s.add_dependency "mvn:org.clojure:clojure", "> 1.3" 17 | end 18 | -------------------------------------------------------------------------------- /examples/simple.rb: -------------------------------------------------------------------------------- 1 | require 'cloby' 2 | 3 | class MyClojureObj < Clojure::Object 4 | def initialize 5 | dosync { @foo = 'foo' } 6 | end 7 | 8 | attr_accessor :foo 9 | end 10 | 11 | obj = MyClojureObj.new 12 | puts "obj.foo = " + obj.foo 13 | 14 | begin 15 | puts "Setting obj.foo to 'bar'" 16 | obj.foo = 'bar' 17 | rescue ConcurrencyError 18 | puts "Oops, need a transaction" 19 | end 20 | 21 | puts "Trying again with a transaction" 22 | dosync { obj.foo = 'bar' } 23 | puts "Success" 24 | 25 | puts "obj.foo = " + obj.foo 26 | -------------------------------------------------------------------------------- /javalib/clojure-1.2.0.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/headius/cloby/28848a6ec7bf8fbdc8832cd8f18b8b9c7ac36a99/javalib/clojure-1.2.0.jar -------------------------------------------------------------------------------- /lib/cloby.rb: -------------------------------------------------------------------------------- 1 | require 'java' 2 | require 'jruby' 3 | 4 | begin 5 | Java::clojure.lang.Ref 6 | rescue Exception 7 | require "mvn:org.clojure:clojure" 8 | begin 9 | Java::clojure.lang.Ref 10 | rescue Exception 11 | fail "Clojure is not available" 12 | end 13 | end 14 | 15 | # load ClojureLibrary 16 | require 'cloby_ext.jar' 17 | org.jruby.clojure.ClojureLibrary.new.load(JRuby.runtime, false) -------------------------------------------------------------------------------- /lib/cloby_ext.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/headius/cloby/28848a6ec7bf8fbdc8832cd8f18b8b9c7ac36a99/lib/cloby_ext.jar -------------------------------------------------------------------------------- /src/org/jruby/clojure/ClojureLibrary.java: -------------------------------------------------------------------------------- 1 | package org.jruby.clojure; 2 | 3 | import clojure.lang.IPersistentVector; 4 | import clojure.lang.LockingTransaction; 5 | import clojure.lang.PersistentVector; 6 | import clojure.lang.Ref; 7 | import java.io.IOException; 8 | import java.util.concurrent.Callable; 9 | import org.jruby.Ruby; 10 | import org.jruby.RubyClass; 11 | import org.jruby.RubyModule; 12 | import org.jruby.RubyObject; 13 | import org.jruby.anno.JRubyMethod; 14 | import org.jruby.runtime.Block; 15 | import org.jruby.runtime.ObjectAllocator; 16 | import org.jruby.runtime.ThreadContext; 17 | import org.jruby.runtime.builtin.IRubyObject; 18 | import org.jruby.runtime.load.Library; 19 | 20 | public class ClojureLibrary implements Library{ 21 | public void load(Ruby runtime, boolean wrap) throws IOException { 22 | RubyModule cljModule = runtime.defineModule("Clojure"); 23 | runtime.defineClassUnder("Object", runtime.getObject(), new ClojureObjectAllocator(), cljModule); 24 | 25 | runtime.getKernel().defineAnnotatedMethods(ClojureDosync.class); 26 | } 27 | 28 | public static class ClojureObjectAllocator implements ObjectAllocator { 29 | public IRubyObject allocate(Ruby runtime, RubyClass klazz) { 30 | return new ClojureObject(runtime, klazz); 31 | } 32 | } 33 | 34 | public static class ClojureObject extends RubyObject { 35 | public ClojureObject(Ruby runtime, RubyClass klass) { 36 | super(runtime, klass); 37 | try { 38 | variableTable = new Ref(PersistentVector.EMPTY); 39 | } catch (Exception e) { 40 | throw runtime.newConcurrencyError(e.getLocalizedMessage()); 41 | } 42 | } 43 | 44 | @Override 45 | public Object getVariable(int index) { 46 | return ((IPersistentVector)variableTable.deref()).nth(index); 47 | } 48 | 49 | @Override 50 | public void setVariable(int index, Object value) { 51 | try { 52 | variableTable.set(((IPersistentVector)variableTable.deref()).assocN(index, value)); 53 | } catch (IllegalStateException ise) { 54 | throw getRuntime().newConcurrencyError(ise.getLocalizedMessage()); 55 | } 56 | } 57 | 58 | private final Ref variableTable; 59 | } 60 | 61 | public static class ClojureDosync { 62 | @JRubyMethod 63 | public static IRubyObject dosync(final ThreadContext context, final IRubyObject self, final Block block) { 64 | final Ruby ruby = context.getRuntime(); 65 | try { 66 | return (IRubyObject)LockingTransaction.runInTransaction(new Callable() { 67 | public Object call() throws Exception { 68 | // re-get transaction in case this gets run in different threads 69 | return block.call(ruby.getCurrentContext()); 70 | } 71 | }); 72 | } catch (Exception e) { 73 | throw ruby.newConcurrencyError(e.getLocalizedMessage()); 74 | } 75 | } 76 | } 77 | } 78 | --------------------------------------------------------------------------------