crequire 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ lib/**/*.rb
2
+ bin/*
3
+ -
4
+ features/**/*.feature
5
+ LICENSE.txt
data/.gitignore ADDED
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ *.swp
4
+ .bundle
5
+ .config
6
+ .yardoc
7
+ Gemfile.lock
8
+ InstalledFiles
9
+ _yardoc
10
+ coverage
11
+ doc/
12
+ lib/bundler/man
13
+ pkg
14
+ rdoc
15
+ spec/reports
16
+ test/tmp
17
+ test/version_tmp
18
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'http://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in crequire.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 Evan Tatarka
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.md ADDED
@@ -0,0 +1,169 @@
1
+ # crequire
2
+
3
+ A simply way to require c code in ruby using SWIG.
4
+
5
+ ## Dependencies
6
+
7
+ * ruby 1.9
8
+ * make
9
+ * SWIG
10
+
11
+ ## A simple example
12
+
13
+ If you have a header file then the functions are detected automatically. You
14
+ can either define the functions in the header file or define a header and
15
+ implementation file separately.
16
+
17
+ ### example1.h
18
+
19
+ ```c
20
+ int fact(int n) {
21
+ if (n <= 1) return 1;
22
+ else return n * fact(n-1);
23
+ }
24
+
25
+ void swap(int *a, int *b) {
26
+ int tmp;
27
+ tmp = *b;
28
+ *b = *a;
29
+ *a = tmp;
30
+ }
31
+ ```
32
+
33
+ ### test_example1.rb
34
+
35
+ ```ruby
36
+ require "crequire"
37
+ crequire "example1"
38
+ include Example1
39
+
40
+ fact(4) => 24
41
+
42
+ a = Intp.new
43
+ a.assign 1
44
+ b = Intp.new
45
+ b.assign 2
46
+
47
+ swap(a, b)
48
+
49
+ a.value => 2
50
+ b.value => 1
51
+ ```
52
+
53
+ ## A complex example
54
+
55
+ If you don't define a header file, you must pass in a block to define the
56
+ method signatures.
57
+
58
+ ### example2.c
59
+
60
+ ```c
61
+ int sum(int a, int b) {
62
+ return a + b;
63
+ }
64
+
65
+ void add(int *x, int *y, int *r) {
66
+ *r = *x + *y;
67
+ }
68
+
69
+ char* echo(char* word) {
70
+ return word;
71
+ }
72
+ ```
73
+
74
+ ### test_example2.rb
75
+
76
+ ```ruby
77
+ require "crequire"
78
+
79
+ # :force => true forces a compile on every run. Alternatively, you can delete
80
+ # the 'example2.o' file for a recompile.
81
+
82
+ crequire "example2", :force => true do
83
+ # To define a function signature, declare the type followed by the function
84
+ # name, passing in the types as symbols or strings.
85
+
86
+ int sum(:int, :int)
87
+
88
+ # To make working with pointers easer, you can define them as *INPUT or
89
+ # *OUTPUT.
90
+
91
+ void add("int *INPUT", "int *INPUT", "int *OUTPUT")
92
+
93
+ # char* is automatically converted to and from string
94
+ char* echo("char*")
95
+ end
96
+
97
+ include Example2
98
+
99
+ sum(1, 2) => 3
100
+ add(3, 4) => 7
101
+ echo("hi") => "hi"
102
+ ```
103
+
104
+ ## Advanced Options
105
+
106
+ You can use ```:src => string``` to pass in the contents of the interface file
107
+ directly.
108
+
109
+ ### example2.c
110
+
111
+ ```c
112
+ int sum(int a, int b, int times) {
113
+ int result = a;
114
+ for (int i = 0; i < times; i++) {
115
+ result += b;
116
+ }
117
+ return result;
118
+ }
119
+ ```
120
+
121
+ ### test_example3.rb
122
+
123
+ ```ruby
124
+ require 'crequire'
125
+
126
+ # ```:interface => directory``` outputs the generated interface file to the given
127
+ # directory. If you want to dump all generated files, you can use
128
+ # ```:dump => directory```.
129
+
130
+
131
+ interface = "%module example3
132
+ %{
133
+ extern int sum(int a, int b, int times);
134
+ %}
135
+ extern int sum(int a, int b, int times);"
136
+
137
+ # You can use ```:cflags => flags``` to set c compiler options.
138
+ crequire "example3", :force => true, :cflags => "-std=c99", :interface => "example3", :src => interface
139
+
140
+ include Example3
141
+
142
+ sum(1, 2, 2) => 5
143
+ ```
144
+
145
+ ### example3/example3.i
146
+
147
+ ```c
148
+ %module example3
149
+ %{
150
+ extern int sum(int a, int b);
151
+ %}
152
+ extern int sum(int a, int b);
153
+ ```
154
+
155
+ ## Contributing to crequire
156
+
157
+ * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
158
+ * Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
159
+ * Fork the project
160
+ * Start a feature/bugfix branch
161
+ * Commit and push until you are happy with your contribution
162
+ * Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
163
+ * Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
164
+
165
+ ## Copyright
166
+
167
+ Copyright (c) 2011 Evan Tatarka. See LICENSE.txt for
168
+ further details.
169
+
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
3
+ require 'rspec/core/rake_task'
4
+
5
+ Bundler::GemHelper.install_tasks
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ task :default => [:spec]
data/crequire.gemspec ADDED
@@ -0,0 +1,19 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/crequire/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.authors = ["Evan Tatarka"]
6
+ gem.email = ["evantatarka@gmail.com"]
7
+ gem.description = %q{A simple way to require c files using swig.}
8
+ gem.summary = %q{A simple way to require c files using swig.}
9
+ gem.homepage = "http://github.com/evant/crequire"
10
+
11
+ gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
12
+ gem.files = `git ls-files`.split("\n")
13
+ gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
14
+ gem.name = "crequire"
15
+ gem.require_paths = ["lib"]
16
+ gem.version = Crequire::VERSION
17
+
18
+ gem.add_development_dependency "rspec", "~> 2.7"
19
+ end
data/lib/crequire.rb ADDED
@@ -0,0 +1,6 @@
1
+ module Crequire
2
+ require "crequire/version"
3
+ require "crequire/swig"
4
+ end
5
+
6
+ require "crequire/crequire"
@@ -0,0 +1,103 @@
1
+ require 'fileutils'
2
+ require 'tmpdir'
3
+
4
+ class Require
5
+ def initialize(file_path)
6
+ @full_path = File.expand_path file_path
7
+ @path = File.dirname @full_path
8
+ @name = File.basename file_path
9
+ end
10
+
11
+ def require(options = {}, &block)
12
+ if options[:force] or !File.exists? "#{@full_path}.o"
13
+
14
+ @src = options[:src]
15
+ @cflags = options[:cflags]
16
+ @dump_interface = options[:interface]
17
+ if options[:dump]
18
+ dir = options[:dump]
19
+ FileUtils.mkpath dir
20
+ save dir, &block
21
+ install dir
22
+ else
23
+ Dir.mktmpdir do |tmp|
24
+ save tmp, &block
25
+ install tmp
26
+ end
27
+ end
28
+ end
29
+
30
+ Kernel.require @name
31
+ end
32
+
33
+ def interface(source=nil, &block)
34
+ if source
35
+ source
36
+ else
37
+ swig = SWIG::Context.new(@name)
38
+ swig.input &block if block
39
+ swig.interface
40
+ end
41
+ end
42
+
43
+ private
44
+
45
+ def save(path, &block)
46
+ save_interface path, &block
47
+ save_extconf path
48
+ end
49
+
50
+ def save_interface(path, &block)
51
+ File.open(File.join(path, "#{@name}.i"), 'w') do |file|
52
+ file << interface(@src, &block)
53
+ end
54
+ end
55
+
56
+ def save_extconf(path)
57
+ File.open(File.join(path, "extconf.rb"), 'w') do |file|
58
+ file << extconf
59
+ end
60
+ end
61
+
62
+ def extconf
63
+ output = "require 'mkmf'\n"
64
+ output << "$CFLAGS << ' #{@cflags}'\n" if @cflags
65
+ output << "create_makefile('#{@name}')"
66
+ end
67
+
68
+ def install(path)
69
+ try_copy "#{@name}.c", path
70
+ try_copy "#{@name}.h", path
71
+
72
+ dir = Dir.pwd
73
+ Dir.chdir path
74
+ `swig -ruby "#{@name}.i"`
75
+ exit if $? != 0
76
+
77
+ `ruby extconf.rb`
78
+ `make`
79
+ `make install`
80
+ Dir.chdir dir
81
+
82
+ output = File.join path, "#{@name}_wrap.o"
83
+ FileUtils.cp output, "#{@full_path}.o"
84
+
85
+ if @dump_interface
86
+ i = File.join path, "#{@name}.i"
87
+ dest = File.join @dump_interface, "#{@name}.i"
88
+ FileUtils.cp i, dest
89
+ end
90
+ end
91
+
92
+ def try_copy(name, path)
93
+ from = File.join @path, name
94
+ to = File.join path, name
95
+ if File.exists? from
96
+ FileUtils.cp from, to
97
+ end
98
+ end
99
+ end
100
+
101
+ def crequire(file_path, options = {}, &block)
102
+ Require.new(file_path).require options, &block
103
+ end
@@ -0,0 +1,29 @@
1
+ module StringHelper
2
+ def charpp(value = nil)
3
+ if value
4
+ Charpp.new(self, self.copy_charpp(value))
5
+ else
6
+ Charpp.new(self, self.new_charpp)
7
+ end
8
+ end
9
+
10
+ class Charpp
11
+ def initialize(type, pointer)
12
+ @type = type
13
+ @pointer = pointer
14
+ end
15
+
16
+ def pointer
17
+ @pointer
18
+ end
19
+
20
+ def value
21
+ type.charpp_value(@pointer)
22
+ end
23
+
24
+ def delete
25
+ type.delete_charpp(@pointer)
26
+ @pointer = nil
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,130 @@
1
+ module SWIG
2
+ class Context
3
+ def initialize(name)
4
+ @name = name
5
+ @functions = []
6
+ @pointers = []
7
+ end
8
+
9
+ def input(&block)
10
+ instance_eval &block
11
+ self
12
+ end
13
+
14
+ def method_missing(m, *args)
15
+ if args.size == 1 and args[0].class <= Function
16
+ func = args[0]
17
+ func.return = m
18
+ @functions << func
19
+ elsif args.size == 0
20
+ Unknown.new(m.to_s, self)
21
+ else
22
+ Function.new(m.to_s, args.map {|arg| arg.to_s})
23
+ end
24
+ end
25
+
26
+ def <<(input)
27
+ @pointers << input if input.is_a? Pointer
28
+ @functions << input if input.is_a? Function
29
+ end
30
+
31
+ def pointer(p, name = nil)
32
+ @pointers << Pointer.new(p, name)
33
+ end
34
+
35
+ def interface
36
+ output = "%module #{@name}\n"
37
+ if @pointers.size > 0
38
+ output << "%include \"cpointer.i\"\n" +
39
+ @pointers.map {|p| p.to_s}.join("\n")
40
+ end
41
+ output << "%{\n"
42
+ output << if @functions.size > 0
43
+ @functions.map {|f| f.to_s}.join("\n")
44
+ else
45
+ "#include \"#{@name}.h\""
46
+ end
47
+ output << "\n%}\n"
48
+ output << if @functions.size > 0
49
+ @functions.map {|f| f.to_swig_s}.join("\n")
50
+ else
51
+ "%include \"#{@name}.h\""
52
+ end
53
+ end
54
+ end
55
+
56
+ class Unknown
57
+ attr_accessor :name, :args
58
+
59
+ def initialize(name, context)
60
+ @context = context
61
+ @name = name
62
+ @args = []
63
+ end
64
+
65
+ def *(other)
66
+ @context << Function.new(other.name, other.args, @name + "*")
67
+ end
68
+
69
+ def to_s
70
+ @context << Function.new(@name).to_sig
71
+ end
72
+
73
+ def to_swig_s
74
+ @context << Function.new(@name).to_swig
75
+ end
76
+ end
77
+
78
+ class Function
79
+ attr_accessor :name, :args, :return
80
+
81
+ def initialize(name, args = [], ret = :void)
82
+ @name = name
83
+ @args = args
84
+ @return = ret
85
+ end
86
+
87
+ def to_s
88
+ res = "extern #{@return} #{@name}("
89
+ res << @args.each_with_index.map do |arg,i|
90
+ if arg =~ /(INPUT)|(OUTPUT)/
91
+ arg.to_s.gsub(/(INPUT)|(OUTPUT)/, "arg#{i}")
92
+ else
93
+ arg.to_s + " arg#{i}"
94
+ end
95
+ end.join(", ")
96
+ res << ");"
97
+ end
98
+
99
+ def to_swig_s
100
+ res = "extern #{@return} #{@name}("
101
+ res << @args.each_with_index.map do |arg,i|
102
+ if arg =~ /(INPUT)|(OUTPUT)/
103
+ arg.to_s
104
+ else
105
+ arg.to_s + " arg#{i}"
106
+ end
107
+ end.join(", ")
108
+ res << ");"
109
+ end
110
+ end
111
+
112
+ class Pointer
113
+ attr_accessor :name, :class_name
114
+
115
+ def initialize(name, class_name)
116
+ @name = name.to_s
117
+ @class_name = class_name ? class_name.to_s : name.to_s + 'p'
118
+ end
119
+
120
+ def to_s
121
+ "%pointer_class(#{@name}, #{camelize(@class_name)});"
122
+ end
123
+
124
+ private
125
+
126
+ def camelize(word)
127
+ word.to_s.gsub(/\/(.?)/) { "::#{$1.upcase}" }.gsub(/(?:^|_)(.)/) { $1.upcase }
128
+ end
129
+ end
130
+ end
@@ -0,0 +1,3 @@
1
+ module Crequire
2
+ VERSION = "0.0.1"
3
+ end
data/spec/add.c ADDED
@@ -0,0 +1,3 @@
1
+ void add(int *x, int *y, int *r) {
2
+ *r = *x + *y;
3
+ }
@@ -0,0 +1,98 @@
1
+ require 'tmpdir'
2
+ require 'fileutils'
3
+ require 'crequire'
4
+
5
+ describe "interface" do
6
+ before :each do
7
+ @crequire = Require.new 'test'
8
+ end
9
+
10
+ it "should use the interface source if given" do
11
+ @crequire.interface("test").should == "test"
12
+ end
13
+
14
+ it "should include the module name" do
15
+ @crequire.interface.should include("%module test")
16
+ end
17
+
18
+ it "should default to including headers" do
19
+ @crequire.interface.should include('#include "test.h"')
20
+ @crequire.interface.should include('%include "test.h"')
21
+ end
22
+
23
+ it "should generate a custom interface correctly" do
24
+ @crequire.interface { int sum(:int, :int) }.should
25
+ include("extern int sum(int arg0, int arg1);")
26
+ end
27
+
28
+ context "with pointers" do
29
+ it "should include cpointer.i" do
30
+ @crequire.interface { pointer :int }.should
31
+ include('%include "cpointer.i"')
32
+ end
33
+
34
+ it "should include a pointer with the given name and class name" do
35
+ @crequire.interface { pointer :int, :int_pointer }.should
36
+ include('%pointer_class(int, IntPointer);')
37
+ end
38
+
39
+ it "should include a pointer with a default class name" do
40
+ @crequire.interface { pointer :int }.should
41
+ include('%pointer_class(int, Intp);')
42
+ end
43
+ end
44
+ end
45
+
46
+ describe "crequire" do
47
+ context "with a simple function" do
48
+ before :all do
49
+ crequire 'spec/fact', :force => true
50
+ end
51
+
52
+ it "should correctly call the function" do
53
+ Fact.fact(4).should == 24
54
+ end
55
+ end
56
+
57
+ context "with a function with INPUT and OUTPUT pointers" do
58
+ before :all do
59
+ crequire 'spec/add', :force => true do
60
+ void add("int *INPUT", "int *INPUT", "int *OUTPUT")
61
+ end
62
+
63
+ it "should correctly call the function" do
64
+ Add.add(1, 2).should == 3
65
+ end
66
+ end
67
+ end
68
+
69
+ context "with a function with char*" do
70
+ before :all do
71
+ crequire 'spec/echo', :force => true do
72
+ char* echo("char*")
73
+ end
74
+ end
75
+
76
+ it "should correctly call the function" do
77
+ Echo.echo("test").should == "test"
78
+ end
79
+ end
80
+
81
+ context "with custom interface input" do
82
+ before :all do
83
+ interface = <<-TEXT
84
+ %module sum
85
+ %{
86
+ extern int sum(int arg0, int arg1);
87
+ %}
88
+ extern int sum(int arg0, int arg1);
89
+ TEXT
90
+
91
+ crequire 'spec/sum', :force => true, :src => interface
92
+ end
93
+
94
+ it "should correctly call the function" do
95
+ Sum.sum(1, 2).should == 3
96
+ end
97
+ end
98
+ end
data/spec/echo.c ADDED
@@ -0,0 +1,3 @@
1
+ char* echo(char* text) {
2
+ return text;
3
+ }
data/spec/echo.o ADDED
Binary file
data/spec/fact.h ADDED
@@ -0,0 +1,4 @@
1
+ int fact(int a) {
2
+ if (a <= 0) return 1;
3
+ else return a * fact(a - 1);
4
+ }
data/spec/fact.o ADDED
Binary file
data/spec/sum.c ADDED
@@ -0,0 +1,3 @@
1
+ int sum(int a, int b) {
2
+ return a + b;
3
+ }
data/spec/sum.o ADDED
Binary file
data/spec/swig_spec.rb ADDED
@@ -0,0 +1,29 @@
1
+ require 'rspec'
2
+ require 'crequire/swig'
3
+
4
+ describe SWIG do
5
+ it "should correctly convert a function to a string" do
6
+ SWIG::Context.new("test").input { int sum(:int, :int) }.interface.should
7
+ include("extern int sum(int arg0, int arg1);")
8
+ end
9
+
10
+ it "should correctly convert a function into a swig signature" do
11
+ SWIG::Context.new("test").input { void add("int *INPUT", "int *INPUT", "int *OUTPUT") }.interface.should
12
+ include("extern void add(int *INPUT, int *INPUT, int *OUTPUT);")
13
+ end
14
+
15
+ it "should correctly parse pointer returned pointers" do
16
+ SWIG::Context.new("test").input { char* echo("char *INPUT") }.to_s.should
17
+ include("extern char* echo(char *arg0);")
18
+ end
19
+
20
+ it "should have the correct pointer_class with default name" do
21
+ SWIG::Context.new("test").input { pointer :int }.interface.should
22
+ include("%pointer_class(int, Intp);")
23
+ end
24
+
25
+ it "should have the correct pointer_class with given name" do
26
+ SWIG::Context.new("test").input { pointer :double, :double_pointer }.interface.should
27
+ include("%pointer_class(double, DoublePointer);")
28
+ end
29
+ end
metadata ADDED
@@ -0,0 +1,77 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: crequire
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Evan Tatarka
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-12-06 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rspec
16
+ requirement: &17167880 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: '2.7'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: *17167880
25
+ description: A simple way to require c files using swig.
26
+ email:
27
+ - evantatarka@gmail.com
28
+ executables: []
29
+ extensions: []
30
+ extra_rdoc_files: []
31
+ files:
32
+ - .document
33
+ - .gitignore
34
+ - Gemfile
35
+ - LICENSE.txt
36
+ - README.md
37
+ - Rakefile
38
+ - crequire.gemspec
39
+ - lib/crequire.rb
40
+ - lib/crequire/crequire.rb
41
+ - lib/crequire/string_helper.rb
42
+ - lib/crequire/swig.rb
43
+ - lib/crequire/version.rb
44
+ - spec/add.c
45
+ - spec/crequire_spec.rb
46
+ - spec/echo.c
47
+ - spec/echo.o
48
+ - spec/fact.h
49
+ - spec/fact.o
50
+ - spec/sum.c
51
+ - spec/sum.o
52
+ - spec/swig_spec.rb
53
+ homepage: http://github.com/evant/crequire
54
+ licenses: []
55
+ post_install_message:
56
+ rdoc_options: []
57
+ require_paths:
58
+ - lib
59
+ required_ruby_version: !ruby/object:Gem::Requirement
60
+ none: false
61
+ requirements:
62
+ - - ! '>='
63
+ - !ruby/object:Gem::Version
64
+ version: '0'
65
+ required_rubygems_version: !ruby/object:Gem::Requirement
66
+ none: false
67
+ requirements:
68
+ - - ! '>='
69
+ - !ruby/object:Gem::Version
70
+ version: '0'
71
+ requirements: []
72
+ rubyforge_project:
73
+ rubygems_version: 1.8.10
74
+ signing_key:
75
+ specification_version: 3
76
+ summary: A simple way to require c files using swig.
77
+ test_files: []