thrifty 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +30 -0
- data/Rakefile +1 -0
- data/examples/userdb/Gemfile +3 -0
- data/examples/userdb/README.md +15 -0
- data/examples/userdb/client.rb +22 -0
- data/examples/userdb/server.rb +26 -0
- data/examples/userdb/service.thrift +10 -0
- data/lib/thrifty/thrift_file.rb +84 -0
- data/lib/thrifty/version.rb +3 -0
- data/lib/thrifty.rb +47 -0
- data/thrifty.gemspec +21 -0
- metadata +93 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Greg Brockman
|
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.
|
data/README.md
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
# Thrifty
|
2
|
+
|
3
|
+
Tired of manually regenerating your Thrift interface code every time
|
4
|
+
the definition changes? Thrifty manages your Thrift interface
|
5
|
+
definitions behind the scenes.
|
6
|
+
|
7
|
+
## Usage
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
require 'thrifty'
|
11
|
+
Thrifty.register('my_interface.thrift')
|
12
|
+
|
13
|
+
Thrifty.require('generated_service')
|
14
|
+
GeneratedService.do_things
|
15
|
+
```
|
16
|
+
|
17
|
+
See the examples directory for a complete working example.
|
18
|
+
|
19
|
+
## Caveats
|
20
|
+
|
21
|
+
You must have a working thrift compiler on your PATH. (That is, you
|
22
|
+
should be able to just type 'thrift'.) Thrifty does not currently
|
23
|
+
statically check that this is the case.
|
24
|
+
|
25
|
+
## TODO
|
26
|
+
|
27
|
+
- Add a precompile mode, similar to how the Rails asset pipeline
|
28
|
+
works.
|
29
|
+
- Statically ensure there's a thrift compiler on the PATH.
|
30
|
+
- Autorequire of all generated Thrift files?
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
@@ -0,0 +1,15 @@
|
|
1
|
+
Simple client/server example from using the Thrift definition file
|
2
|
+
from http://thrift.apache.org/.
|
3
|
+
|
4
|
+
To test it out, do the following:
|
5
|
+
|
6
|
+
- Run 'bundle'
|
7
|
+
- Run 'bundle exec ruby server.rb' in one terminal. Leave it running.
|
8
|
+
- Run 'bundle exec ruby client.rb' in another terminal.
|
9
|
+
|
10
|
+
You should see something like the following from the client:
|
11
|
+
|
12
|
+
```
|
13
|
+
Storing <UserProfile uid:1234, name:"my name!", blurb:"your name!">
|
14
|
+
Retrieved <UserProfile uid:1234, name:"my name!", blurb:"your name!">
|
15
|
+
```
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'thrifty'
|
2
|
+
Thrifty.register('service.thrift')
|
3
|
+
Thrifty.require('user_storage')
|
4
|
+
|
5
|
+
port = ARGV[0] || 9090
|
6
|
+
|
7
|
+
transport = Thrift::BufferedTransport.new(Thrift::Socket.new('127.0.0.1', 9090))
|
8
|
+
protocol = Thrift::BinaryProtocol.new(transport)
|
9
|
+
client = UserStorage::Client.new(protocol)
|
10
|
+
|
11
|
+
transport.open
|
12
|
+
|
13
|
+
profile = UserProfile.new
|
14
|
+
profile.uid = 1234
|
15
|
+
profile.name = 'my name!'
|
16
|
+
profile.blurb = 'your name!'
|
17
|
+
|
18
|
+
puts "Storing #{profile.inspect}"
|
19
|
+
client.store(profile)
|
20
|
+
|
21
|
+
retrieved = client.retrieve(1234)
|
22
|
+
puts "Retrieved #{retrieved.inspect}"
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'thrifty'
|
2
|
+
Thrifty.register('service.thrift')
|
3
|
+
Thrifty.require('user_storage')
|
4
|
+
|
5
|
+
class UserStorageServer
|
6
|
+
def initialize
|
7
|
+
@store = {}
|
8
|
+
end
|
9
|
+
|
10
|
+
def store(user_profile)
|
11
|
+
@store[user_profile.uid] = user_profile
|
12
|
+
end
|
13
|
+
|
14
|
+
def retrieve(uid)
|
15
|
+
@store[uid]
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
handler = UserStorageServer.new
|
20
|
+
processor = UserStorage::Processor.new(handler)
|
21
|
+
transport = Thrift::ServerSocket.new(9090)
|
22
|
+
transportFactory = Thrift::BufferedTransportFactory.new()
|
23
|
+
server = Thrift::SimpleServer.new(processor, transport, transportFactory)
|
24
|
+
|
25
|
+
puts "Booting user storage server..."
|
26
|
+
server.serve
|
@@ -0,0 +1,84 @@
|
|
1
|
+
require 'digest/sha1'
|
2
|
+
require 'fileutils'
|
3
|
+
require 'rubysh'
|
4
|
+
|
5
|
+
module Thrifty
|
6
|
+
class ThriftFile
|
7
|
+
attr_reader :thrift_file
|
8
|
+
|
9
|
+
def initialize(thrift_file)
|
10
|
+
@thrift_file = thrift_file
|
11
|
+
end
|
12
|
+
|
13
|
+
def defines?(generated_file)
|
14
|
+
compile_once
|
15
|
+
File.exists?(File.join(build_directory, generated_file + '.rb'))
|
16
|
+
end
|
17
|
+
|
18
|
+
def require(generated_file)
|
19
|
+
compile_once
|
20
|
+
$:.unshift(build_directory)
|
21
|
+
|
22
|
+
begin
|
23
|
+
Thrifty.logger.info("Requiring #{generated_file.inspect}, generated from #{thrift_file.inspect}")
|
24
|
+
# Global require
|
25
|
+
super(generated_file)
|
26
|
+
ensure
|
27
|
+
# Not sure what to do if someone changed $: in the
|
28
|
+
# meanwhile. Could happen due a signal handler or something
|
29
|
+
# crazy like that.
|
30
|
+
if $:.first == build_directory
|
31
|
+
$:.shift
|
32
|
+
else
|
33
|
+
Thrifty.logger.error("Unexpected first element in load path; not removing #{build_directory.inspect}: #{$:.inspect}")
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def compile_once
|
39
|
+
with_cache do
|
40
|
+
FileUtils.mkdir_p(build_directory)
|
41
|
+
Rubysh('thrift', '--gen', 'rb', '-out', build_directory, thrift_file).check_call
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def with_cache(&blk)
|
48
|
+
raise "No such Thrift file #{thrift_file.inspect}" unless File.exists?(thrift_file)
|
49
|
+
|
50
|
+
# There's obviously a race if someone changes the file before
|
51
|
+
# the compiler runs, so we capture the sha1 up front so it'll at
|
52
|
+
# least be more likely to falsely invalidate the cache.
|
53
|
+
new_version = Digest::SHA1.file(thrift_file).to_s
|
54
|
+
cached_version = File.read(version_file) if File.exists?(version_file)
|
55
|
+
|
56
|
+
# cached_version will be nil if the cache doesn't exist, so always miss.
|
57
|
+
if new_version == cached_version
|
58
|
+
Thrifty.logger.debug("Using cached version")
|
59
|
+
return
|
60
|
+
end
|
61
|
+
|
62
|
+
Thrifty.logger.info("Compiling thrift file #{thrift_file} with SHA1 #{new_version} to #{build_directory}")
|
63
|
+
blk.call
|
64
|
+
|
65
|
+
File.open(version_file, 'w') {|f| f.write(new_version)}
|
66
|
+
end
|
67
|
+
|
68
|
+
def version_file
|
69
|
+
File.join(build_directory, 'VERSION')
|
70
|
+
end
|
71
|
+
|
72
|
+
def build_directory
|
73
|
+
# Use the basename for informational purposes, and the SHA1 for
|
74
|
+
# avoid collisions.
|
75
|
+
base = File.basename(thrift_file)
|
76
|
+
sha1 = Digest::SHA1.hexdigest(thrift_file)
|
77
|
+
File.join(basedir, "#{base}-#{sha1}")
|
78
|
+
end
|
79
|
+
|
80
|
+
def basedir
|
81
|
+
Thrifty.basedir
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
data/lib/thrifty.rb
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'logger'
|
2
|
+
require 'tmpdir'
|
3
|
+
|
4
|
+
require 'thrift'
|
5
|
+
|
6
|
+
require 'thrifty/thrift_file'
|
7
|
+
require 'thrifty/version'
|
8
|
+
|
9
|
+
module Thrifty
|
10
|
+
@thrift_files = {}
|
11
|
+
|
12
|
+
def self.logger
|
13
|
+
@logger ||= begin
|
14
|
+
logger = Logger.new(STDOUT)
|
15
|
+
logger.level = Logger::ERROR
|
16
|
+
logger
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.basedir
|
21
|
+
@basedir ||= Dir.tmpdir
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.basedir=(basedir)
|
25
|
+
@basedir = basedir
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.register(thrift_file)
|
29
|
+
raise "File already registered: #{thrift_file.inspect}" if @thrift_files.include?(thrift_file)
|
30
|
+
@thrift_files[thrift_file] = Thrifty::ThriftFile.new(thrift_file)
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.require(generated_file)
|
34
|
+
definers = @thrift_files.values.select do |thrift_file|
|
35
|
+
thrift_file.defines?(generated_file)
|
36
|
+
end
|
37
|
+
|
38
|
+
if definers.length == 0
|
39
|
+
raise LoadError, "No registered thrift file defines #{generated_file.inspect}. Perhaps you forgot to run `Thrifty.register(thrift_file)`?"
|
40
|
+
elsif definers.length == 1
|
41
|
+
definer = definers.first
|
42
|
+
definer.require(generated_file)
|
43
|
+
else
|
44
|
+
raise LoadError, "Ambiguous generated file #{generated_file.inspect} defined in #{definers.map {|definer| definer.thrift_file.inspect}.join(', ')}"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
data/thrifty.gemspec
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'thrifty/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |gem|
|
7
|
+
gem.name = "thrifty"
|
8
|
+
gem.version = Thrifty::VERSION
|
9
|
+
gem.authors = ["Greg Brockman"]
|
10
|
+
gem.email = ["gdb@gregbrockman.com"]
|
11
|
+
gem.description = "Automatically compile Thrift definitions in Ruby"
|
12
|
+
gem.summary = "Begone manual compilation of Thrift definitions! Thrifty makes it easy to automatically manage your Thrift definitions."
|
13
|
+
gem.homepage = ""
|
14
|
+
|
15
|
+
gem.files = `git ls-files`.split($/)
|
16
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
17
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
18
|
+
gem.require_paths = ["lib"]
|
19
|
+
gem.add_dependency 'thrift'
|
20
|
+
gem.add_dependency 'rubysh'
|
21
|
+
end
|
metadata
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: thrifty
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Greg Brockman
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-04-28 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: thrift
|
16
|
+
requirement: !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: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: rubysh
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
description: Automatically compile Thrift definitions in Ruby
|
47
|
+
email:
|
48
|
+
- gdb@gregbrockman.com
|
49
|
+
executables: []
|
50
|
+
extensions: []
|
51
|
+
extra_rdoc_files: []
|
52
|
+
files:
|
53
|
+
- .gitignore
|
54
|
+
- Gemfile
|
55
|
+
- LICENSE.txt
|
56
|
+
- README.md
|
57
|
+
- Rakefile
|
58
|
+
- examples/userdb/Gemfile
|
59
|
+
- examples/userdb/README.md
|
60
|
+
- examples/userdb/client.rb
|
61
|
+
- examples/userdb/server.rb
|
62
|
+
- examples/userdb/service.thrift
|
63
|
+
- lib/thrifty.rb
|
64
|
+
- lib/thrifty/thrift_file.rb
|
65
|
+
- lib/thrifty/version.rb
|
66
|
+
- thrifty.gemspec
|
67
|
+
homepage: ''
|
68
|
+
licenses: []
|
69
|
+
post_install_message:
|
70
|
+
rdoc_options: []
|
71
|
+
require_paths:
|
72
|
+
- lib
|
73
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
74
|
+
none: false
|
75
|
+
requirements:
|
76
|
+
- - ! '>='
|
77
|
+
- !ruby/object:Gem::Version
|
78
|
+
version: '0'
|
79
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
80
|
+
none: false
|
81
|
+
requirements:
|
82
|
+
- - ! '>='
|
83
|
+
- !ruby/object:Gem::Version
|
84
|
+
version: '0'
|
85
|
+
requirements: []
|
86
|
+
rubyforge_project:
|
87
|
+
rubygems_version: 1.8.23
|
88
|
+
signing_key:
|
89
|
+
specification_version: 3
|
90
|
+
summary: Begone manual compilation of Thrift definitions! Thrifty makes it easy to
|
91
|
+
automatically manage your Thrift definitions.
|
92
|
+
test_files: []
|
93
|
+
has_rdoc:
|