thrifty 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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:
|