fluent-tools 0.2.0

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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 807b6f8dbd3ccbbb76cbb8420d6093b250e88608a8a90c8fb0eda55f87bbf22c
4
+ data.tar.gz: 0533e6d8cfd25c021486c0b56931843347adb96fdb6b8ae3ba28021db8596547
5
+ SHA512:
6
+ metadata.gz: 4a538a4801bfab70efc3635c2f6bc492ff866cac46222291b59fa8893fbfeaef225dc60e64e5503c556d41d12ef1c2e890117704e480b0b69cb971b6df28011a
7
+ data.tar.gz: bafabd8faabf050e41ce921ea69e9c6a5d3e950c0006ef3c50a1cb1c78112cac68d1ae4f3829c3bf380309ffbf114bdf3e6da10f542780dd1be9bfbbe829db0f
data/exe/fluent-tools ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require_relative '../lib/fluent_tools'
5
+
6
+ FluentTools::CLI.start(ARGV)
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../installer'
4
+ require_relative '../../lib/fluent_tools/version'
5
+ require 'fileutils'
6
+
7
+ puts "Installing fluent-tools #{FluentTools::VERSION}..."
8
+
9
+ # Create installer instance for gem context with version
10
+ installer = FluentToolsInstaller.new(version: FluentTools::VERSION)
11
+
12
+ # Run installation
13
+ success = installer.install!
14
+
15
+ # Ensure the bin directory exists and is included in the gem
16
+ bin_dir = File.expand_path('../../bin', __dir__)
17
+ FileUtils.mkdir_p(bin_dir)
18
+
19
+ # Create dummy Makefile for RubyGems compatibility
20
+ makefile_content = <<~MAKEFILE
21
+ all:
22
+ \t@echo 'Binary already installed'
23
+
24
+ install:
25
+ \t@echo 'Binary already installed'
26
+
27
+ clean:
28
+ \t@echo 'Nothing to clean'
29
+ MAKEFILE
30
+
31
+ File.write('Makefile', makefile_content)
32
+
33
+ unless success
34
+ puts '❌ Installation failed - binary could not be installed'
35
+ puts 'This may still work if the binary becomes available at runtime'
36
+ puts 'or if you build it manually using: rake build_rust'
37
+ exit 1
38
+ end
39
+
40
+ puts '✅ Extension configuration complete'
data/installer.rb ADDED
@@ -0,0 +1,212 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ # Installer for fluent-rust-tools gem
5
+ # Used by extconf.rb during gem installation
6
+
7
+ require 'net/http'
8
+ require 'uri'
9
+ require 'fileutils'
10
+ require 'rbconfig'
11
+ require 'json'
12
+ require 'pathname'
13
+ require_relative 'lib/fluent_tools/utils'
14
+
15
+ # Installer for fluent-rust-tools gem
16
+ # Downloads pre-built binaries or builds from source
17
+ class FluentToolsInstaller
18
+ include FluentTools::Utils::Logger
19
+
20
+ def initialize(version: nil)
21
+ @version = version
22
+ end
23
+
24
+ # Main installation method
25
+ def install!
26
+ log_info "🚀 Installing #{FluentTools::Utils::BINARY_NAME}#{" `#{@version}`" if @version}..."
27
+
28
+ platform = FluentTools::Utils.detect_platform
29
+ if platform
30
+ log_info "🔍 Detected platform: #{platform}"
31
+
32
+ if download_prebuilt_binary(platform)
33
+ log_success 'Installation complete using pre-built binary!'
34
+ true
35
+ else
36
+ log_warning 'Pre-built binary not available, falling back to compilation...'
37
+ build_binary_from_source
38
+ end
39
+ else
40
+ log_warning "Platform #{RUBY_PLATFORM} not supported for pre-built binaries"
41
+ build_binary_from_source
42
+ end
43
+ end
44
+
45
+ private
46
+
47
+ def download_prebuilt_binary(platform)
48
+ log_info "🔍 Attempting to download pre-built binary for #{platform}..."
49
+
50
+ begin
51
+ release_data = @version ? fetch_release_by_version(@version) : fetch_latest_release
52
+ download_url = find_download_url(release_data, platform)
53
+
54
+ return false unless download_url
55
+
56
+ log_info "📦 Downloading from #{download_url}"
57
+ binary_data = download_file(download_url)
58
+
59
+ install_binary(binary_data, platform)
60
+ log_success 'Pre-built binary downloaded successfully!'
61
+ true
62
+ rescue StandardError => e
63
+ if @version
64
+ log_error "Failed to download pre-built binary for version #{@version}: #{e.message}"
65
+ else
66
+ log_error "Failed to download pre-built binary: #{e.message}"
67
+ end
68
+ false
69
+ end
70
+ end
71
+
72
+ def fetch_latest_release
73
+ api_url = "https://api.github.com/repos/#{FluentTools::Utils::REPO_OWNER}/#{FluentTools::Utils::REPO_NAME}/releases/latest"
74
+ uri = URI(api_url)
75
+ response = Net::HTTP.get_response(uri)
76
+
77
+ raise "Could not fetch release information (HTTP #{response.code})" unless response.code == '200'
78
+
79
+ JSON.parse(response.body)
80
+ end
81
+
82
+ def fetch_release_by_version(version)
83
+ api_url = "https://api.github.com/repos/#{FluentTools::Utils::REPO_OWNER}/#{FluentTools::Utils::REPO_NAME}/releases/tags/#{version}"
84
+ uri = URI(api_url)
85
+ response = Net::HTTP.get_response(uri)
86
+
87
+ case response.code
88
+ when '200'
89
+ JSON.parse(response.body)
90
+ when '404'
91
+ raise "Release #{version} not found. Available releases can be viewed at: https://github.com/#{FluentTools::Utils::REPO_OWNER}/#{FluentTools::Utils::REPO_NAME}/releases"
92
+ else
93
+ raise "Could not fetch release #{version} (HTTP #{response.code})"
94
+ end
95
+ end
96
+
97
+ def find_download_url(release_data, platform)
98
+ binary_name = FluentTools::Utils.binary_name_for_platform(platform)
99
+
100
+ asset = release_data['assets'].find { |a| a['name'] == binary_name }
101
+
102
+ unless asset
103
+ log_error "No pre-built binary found for #{platform}"
104
+ return nil
105
+ end
106
+
107
+ asset['browser_download_url']
108
+ end
109
+
110
+ def download_file(url)
111
+ uri = URI(url)
112
+
113
+ Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == 'https') do |http|
114
+ request = Net::HTTP::Get.new(uri)
115
+ response = http.request(request)
116
+
117
+ # Follow redirects (GitHub releases use them)
118
+ case response
119
+ when Net::HTTPRedirection
120
+ download_file(response['location'])
121
+ when Net::HTTPSuccess
122
+ response.body
123
+ else
124
+ raise "Download failed: HTTP #{response.code} - #{response.message}"
125
+ end
126
+ end
127
+ end
128
+
129
+ def install_binary(binary_data, platform)
130
+ install_dir = determine_install_dir
131
+ FileUtils.mkdir_p(install_dir)
132
+
133
+ binary_extension = FluentTools::Utils.binary_extension(platform)
134
+ binary_path = File.join(install_dir, "#{FluentTools::Utils::BINARY_NAME}#{binary_extension}")
135
+
136
+ log_info "📁 Installing binary to: #{binary_path}"
137
+ log_info "📏 Binary data size: #{binary_data.length} bytes"
138
+
139
+ raise 'Downloaded binary data is empty' if binary_data.empty?
140
+
141
+ File.binwrite(binary_path, binary_data)
142
+
143
+ # Make executable on Unix-like systems
144
+ File.chmod(0o755, binary_path) unless FluentTools::Utils.windows_platform?(platform)
145
+
146
+ log_info "✅ Binary installed successfully (#{File.size(binary_path)} bytes)"
147
+ @binary_path = binary_path
148
+ end
149
+
150
+ # rubocop:disable Naming/PredicateMethod
151
+ def build_binary_from_source
152
+ log_info '🔨 Building from source...'
153
+
154
+ # Find project root (where Cargo.toml and Makefile are)
155
+ project_root = find_project_root
156
+ unless project_root
157
+ log_error 'Could not find project root (Cargo.toml)'
158
+ return false
159
+ end
160
+
161
+ # Use Makefile to build the binary
162
+ Dir.chdir(project_root) do
163
+ unless system('make build_native')
164
+ log_error 'Failed to build Rust binary using Makefile'
165
+ return false
166
+ end
167
+ end
168
+
169
+ # Copy binary to install location
170
+ copy_built_binary(project_root)
171
+ log_success 'Binary built and installed successfully!'
172
+
173
+ true
174
+ end
175
+ # rubocop:enable Naming/PredicateMethod
176
+
177
+ def find_project_root
178
+ Pathname.pwd.ascend do |dir|
179
+ return dir.to_s if File.exist?(File.join(dir, 'Cargo.toml'))
180
+ end
181
+ nil
182
+ end
183
+
184
+ def copy_built_binary(project_root)
185
+ install_dir = determine_install_dir
186
+ FileUtils.mkdir_p(install_dir)
187
+
188
+ binary_extension = FluentTools::Utils.binary_extension
189
+ source_binary = File.join(project_root, 'target', 'release', "#{FluentTools::Utils::BINARY_NAME}#{binary_extension}")
190
+ dest_binary = File.join(install_dir, "#{FluentTools::Utils::BINARY_NAME}#{binary_extension}")
191
+
192
+ raise "Built binary not found at #{source_binary}" unless File.exist?(source_binary)
193
+
194
+ FileUtils.cp(source_binary, dest_binary)
195
+ @binary_path = dest_binary
196
+ end
197
+
198
+ def determine_install_dir
199
+ # First check if we're in the development context (has Cargo.toml in parent dirs)
200
+ project_root = find_project_root
201
+ if project_root
202
+ # Development context - put in ruby/bin relative to project root
203
+ File.join(project_root, 'ruby', 'bin')
204
+ else
205
+ # We're in a gem installation context - create bin directory in current gem location
206
+ current_dir = File.expand_path('..', __dir__)
207
+ bin_dir = File.join(current_dir, 'bin')
208
+ FileUtils.mkdir_p(bin_dir)
209
+ bin_dir
210
+ end
211
+ end
212
+ end
@@ -0,0 +1,96 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'thor'
4
+
5
+ module FluentTools
6
+ # CLI commands for Android XML conversion
7
+ class AndroidCLI < Thor
8
+ desc 'from_fluent INPUT OUTPUT', 'Convert Fluent file to Android XML strings'
9
+ long_desc <<~DESC
10
+ Convert a Fluent localization file to Android XML string resources.
11
+
12
+ INPUT: Path to the input Fluent (.ftl) file
13
+ OUTPUT: Path to the output Android XML file
14
+ DESC
15
+ def from_fluent(input, output)
16
+ command_executor = CommandExecutor.new
17
+ command_executor.fluent_to_android(input, output)
18
+ puts "Successfully converted #{input} to #{output}"
19
+ rescue Error => e
20
+ puts "Error: #{e.message}"
21
+ exit 1
22
+ end
23
+
24
+ desc 'to_fluent INPUT OUTPUT', 'Convert Android XML strings to Fluent file'
25
+ long_desc <<~DESC
26
+ Convert Android XML string resources to a Fluent localization file.
27
+
28
+ INPUT: Path to the input Android XML file
29
+ OUTPUT: Path to the output Fluent (.ftl) file
30
+ DESC
31
+ option :original_fluent, aliases: '-o', desc: 'Original Fluent file for variable mapping recovery'
32
+ def to_fluent(input, output)
33
+ command_executor = CommandExecutor.new
34
+ command_executor.android_to_fluent(input, output, original_fluent: options[:original_fluent])
35
+
36
+ message = "Successfully converted #{input} to #{output}"
37
+ message += " using original Fluent file #{options[:original_fluent]}" if options[:original_fluent]
38
+ puts message
39
+ rescue Error => e
40
+ puts "Error: #{e.message}"
41
+ exit 1
42
+ end
43
+ end
44
+
45
+ # CLI commands for PO (GNU gettext) conversion
46
+ class PoCLI < Thor
47
+ desc 'from_fluent INPUT OUTPUT', 'Convert Fluent file to PO format'
48
+ long_desc <<~DESC
49
+ Convert a Fluent localization file to GNU gettext PO format.
50
+
51
+ INPUT: Path to the input Fluent (.ftl) file
52
+ OUTPUT: Path to the output PO file
53
+ DESC
54
+ option :locale, aliases: '-l', default: 'en-US', desc: 'Source locale (e.g., en-US)'
55
+ def from_fluent(input, output)
56
+ command_executor = CommandExecutor.new
57
+ command_executor.fluent_to_po(input, output, locale: options[:locale])
58
+ puts "Successfully converted #{input} to #{output}"
59
+ rescue Error => e
60
+ puts "Error: #{e.message}"
61
+ exit 1
62
+ end
63
+
64
+ desc 'to_fluent INPUT OUTPUT', 'Convert PO file to Fluent format'
65
+ long_desc <<~DESC
66
+ Convert a GNU gettext PO file to Fluent localization format.
67
+
68
+ INPUT: Path to the input PO file
69
+ OUTPUT: Path to the output Fluent (.ftl) file
70
+ DESC
71
+ def to_fluent(input, output)
72
+ command_executor = CommandExecutor.new
73
+ command_executor.po_to_fluent(input, output)
74
+ puts "Successfully converted #{input} to #{output}"
75
+ rescue Error => e
76
+ puts "Error: #{e.message}"
77
+ exit 1
78
+ end
79
+ end
80
+
81
+ # Main CLI interface with subcommands for different formats
82
+ class CLI < Thor
83
+ # Android conversion commands
84
+ desc 'android SUBCOMMAND', 'Android XML conversion commands'
85
+ subcommand 'android', AndroidCLI
86
+
87
+ # PO conversion commands
88
+ desc 'po SUBCOMMAND', 'PO (GNU gettext) conversion commands'
89
+ subcommand 'po', PoCLI
90
+
91
+ desc 'version', 'Show version'
92
+ def version
93
+ puts "#{FluentTools::Utils::BINARY_NAME} #{VERSION}"
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,127 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'open3'
4
+ require 'pathname'
5
+ require 'fileutils'
6
+
7
+ module FluentTools
8
+ # Core command executor class that interfaces with the fluent-tools Rust binary
9
+ # Handles file validation, output directory creation, and command execution
10
+ class CommandExecutor
11
+ def initialize
12
+ @binary_path = find_binary_path
13
+ end
14
+
15
+ # Convert Fluent file to Android XML
16
+ def fluent_to_android(input_path, output_path)
17
+ validate_input_file!(input_path)
18
+ ensure_output_directory(output_path)
19
+
20
+ cmd = [@binary_path, 'android', 'from-fluent', '-i', input_path, '-o', output_path]
21
+ execute_command(cmd)
22
+ end
23
+
24
+ # Convert Android XML to Fluent file
25
+ def android_to_fluent(input_path, output_path, original_fluent: nil)
26
+ validate_input_file!(input_path)
27
+ ensure_output_directory(output_path)
28
+
29
+ cmd = [@binary_path, 'android', 'to-fluent', '-i', input_path, '-o', output_path]
30
+ cmd += ['--original-fluent', original_fluent] if original_fluent
31
+
32
+ execute_command(cmd)
33
+ end
34
+
35
+ # Convert Fluent file to PO
36
+ def fluent_to_po(input_path, output_path, locale: 'en-US')
37
+ validate_input_file!(input_path)
38
+ ensure_output_directory(output_path)
39
+
40
+ cmd = [@binary_path, 'po', 'from-fluent', '-i', input_path, '-o', output_path, '-l', locale]
41
+ execute_command(cmd)
42
+ end
43
+
44
+ # Convert PO file to Fluent
45
+ def po_to_fluent(input_path, output_path)
46
+ validate_input_file!(input_path)
47
+ ensure_output_directory(output_path)
48
+
49
+ cmd = [@binary_path, 'po', 'to-fluent', '-i', input_path, '-o', output_path]
50
+ execute_command(cmd)
51
+ end
52
+
53
+ private
54
+
55
+ def find_binary_path
56
+ binary_name = FluentTools::Utils::BINARY_NAME
57
+
58
+ # 1. Standard gem installation (works for all gem contexts)
59
+ gem_binary = File.join(__dir__, '..', '..', 'bin', binary_name)
60
+ return gem_binary if File.executable?(gem_binary)
61
+
62
+ # 2. Development context
63
+ if development_context?
64
+ dev_binary = File.join(project_root, 'target', 'release', binary_name)
65
+ return dev_binary if File.executable?(dev_binary)
66
+
67
+ ruby_binary = File.join(project_root, 'ruby', 'bin', binary_name)
68
+ return ruby_binary if File.executable?(ruby_binary)
69
+ end
70
+
71
+ # 3. System PATH
72
+ system_binary = `which #{binary_name} 2>/dev/null`.strip
73
+ return system_binary unless system_binary.empty?
74
+
75
+ # If nothing found, return the expected gem path for better error messages
76
+ gem_binary
77
+ end
78
+
79
+ def development_context?
80
+ !project_root.nil?
81
+ end
82
+
83
+ def project_root
84
+ @project_root ||= find_project_root
85
+ end
86
+
87
+ def find_project_root
88
+ Pathname.new(__dir__).ascend do |dir|
89
+ return dir.to_s if File.exist?(File.join(dir, 'Cargo.toml'))
90
+ end
91
+ nil
92
+ end
93
+
94
+ def validate_input_file!(path)
95
+ return if File.exist?(path)
96
+
97
+ raise Error, "Input file does not exist: #{path}"
98
+ end
99
+
100
+ def ensure_output_directory(path)
101
+ output_dir = File.dirname(path)
102
+ return if Dir.exist?(output_dir)
103
+
104
+ begin
105
+ FileUtils.mkdir_p(output_dir)
106
+ rescue StandardError => e
107
+ raise Error, "Failed to create output directory #{output_dir}: #{e.message}"
108
+ end
109
+ end
110
+
111
+ def execute_command(cmd)
112
+ unless File.executable?(@binary_path)
113
+ raise Error, "Binary not found or not executable: #{@binary_path}. " \
114
+ 'Make sure the gem was installed correctly and Rust is available.'
115
+ end
116
+
117
+ stdout, stderr, status = Open3.capture3(*cmd)
118
+
119
+ unless status.success?
120
+ error_message = stderr.empty? ? stdout : stderr
121
+ raise Error, "Command failed: #{error_message}"
122
+ end
123
+
124
+ stdout
125
+ end
126
+ end
127
+ end
@@ -0,0 +1,103 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rbconfig'
4
+
5
+ module FluentTools
6
+ # Shared utilities for fluent-tools
7
+ module Utils
8
+ # Project constants
9
+ REPO_OWNER = 'Automattic'
10
+ BINARY_NAME = 'fluent-tools'
11
+ REPO_NAME = 'fluent-rust-tools'
12
+
13
+ # Platform to Rust target mapping
14
+ PLATFORM_RUST_TARGETS = {
15
+ 'x86_64-linux' => 'x86_64-unknown-linux-gnu',
16
+ 'arm64-linux' => 'aarch64-unknown-linux-gnu',
17
+ 'x86_64-darwin' => 'x86_64-apple-darwin',
18
+ 'arm64-darwin' => 'aarch64-apple-darwin',
19
+ 'x86_64-windows' => 'x86_64-pc-windows-gnu',
20
+ 'arm64-windows' => 'aarch64-pc-windows-gnullvm'
21
+ }.freeze
22
+
23
+ # Platform detection using RbConfig to identify the current system
24
+ # Returns a string in the format "{architecture}-{os}" (e.g., "arm64-darwin")
25
+ # Returns nil if the platform is not supported
26
+ def self.detect_platform
27
+ host_os = RbConfig::CONFIG['host_os']
28
+ host_cpu = RbConfig::CONFIG['host_cpu']
29
+
30
+ platform = case host_os
31
+ when /linux/
32
+ 'linux'
33
+ when /darwin/
34
+ 'darwin'
35
+ when /mingw|mswin/
36
+ 'windows'
37
+ else
38
+ return nil
39
+ end
40
+
41
+ architecture = case host_cpu
42
+ when /x86_64|amd64/
43
+ 'x86_64'
44
+ when /arm64|aarch64/
45
+ 'arm64'
46
+ else
47
+ return nil
48
+ end
49
+
50
+ "#{architecture}-#{platform}"
51
+ end
52
+
53
+ # Generate the expected binary name for a given platform
54
+ # Adds .exe extension for Windows platforms
55
+ def self.binary_name_for_platform(platform)
56
+ extension = binary_extension(platform)
57
+ "#{BINARY_NAME}-#{platform}#{extension}"
58
+ end
59
+
60
+ # Check if the current platform is Windows
61
+ def self.windows_platform?(platform = nil)
62
+ platform ||= detect_platform
63
+ platform&.include?('windows') || false
64
+ end
65
+
66
+ # Get binary extension for current platform
67
+ def self.binary_extension(platform = nil)
68
+ windows_platform?(platform) ? '.exe' : ''
69
+ end
70
+
71
+ # Validate that a platform is supported
72
+ def self.validate_platform!(platform)
73
+ return if PLATFORM_RUST_TARGETS.key?(platform)
74
+
75
+ raise "Invalid platform: #{platform}. Valid platforms: #{PLATFORM_RUST_TARGETS.keys.join(', ')}"
76
+ end
77
+
78
+ # Convert platform name to Rust target triple
79
+ def self.platform_to_rust_target(platform)
80
+ validate_platform!(platform)
81
+ PLATFORM_RUST_TARGETS[platform]
82
+ end
83
+
84
+ # Logger mixin to provide consistent logging across tools
85
+ module Logger
86
+ def log_info(message, verbose: true)
87
+ puts message if verbose
88
+ end
89
+
90
+ def log_success(message, verbose: true)
91
+ puts "✅ #{message}" if verbose
92
+ end
93
+
94
+ def log_warning(message, verbose: true)
95
+ puts "⚠️ #{message}" if verbose
96
+ end
97
+
98
+ def log_error(message, verbose: true)
99
+ warn "❌ #{message}" if verbose
100
+ end
101
+ end
102
+ end
103
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FluentTools
4
+ VERSION = '0.2.0'
5
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'fluent_tools/version'
4
+ require_relative 'fluent_tools/utils'
5
+ require_relative 'fluent_tools/command_executor'
6
+ require_relative 'fluent_tools/cli'
7
+
8
+ # Ruby bindings and CLI for fluent-rust-tools
9
+ # Provides conversion between Fluent, Android XML, and PO formats
10
+ module FluentTools
11
+ # Custom error class for fluent-tools operations
12
+ class Error < StandardError; end
13
+
14
+ # Convenience method for converting Fluent to Android XML
15
+ def self.fluent_to_android(input_path, output_path)
16
+ CommandExecutor.new.fluent_to_android(input_path, output_path)
17
+ end
18
+
19
+ # Convenience method for converting Android XML to Fluent
20
+ def self.android_to_fluent(input_path, output_path, original_fluent: nil)
21
+ CommandExecutor.new.android_to_fluent(input_path, output_path, original_fluent: original_fluent)
22
+ end
23
+
24
+ # Convenience method for converting Fluent to PO
25
+ def self.fluent_to_po(input_path, output_path, locale: 'en-US')
26
+ CommandExecutor.new.fluent_to_po(input_path, output_path, locale: locale)
27
+ end
28
+
29
+ # Convenience method for converting PO to Fluent
30
+ def self.po_to_fluent(input_path, output_path)
31
+ CommandExecutor.new.po_to_fluent(input_path, output_path)
32
+ end
33
+ end
metadata ADDED
@@ -0,0 +1,105 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fluent-tools
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.0
5
+ platform: ruby
6
+ authors:
7
+ - Automattic
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2025-07-02 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: thor
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rubocop-rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rubocop-rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ description: A Ruby gem that wraps a Rust CLI tool for converting between Mozilla's
56
+ Fluent localization format and other formats like Android XML string resources and
57
+ GNU gettext PO files
58
+ email:
59
+ - mobile@automattic.com
60
+ executables:
61
+ - fluent-tools
62
+ extensions:
63
+ - ext/fluent_tools/extconf.rb
64
+ extra_rdoc_files: []
65
+ files:
66
+ - exe/fluent-tools
67
+ - ext/fluent_tools/extconf.rb
68
+ - installer.rb
69
+ - lib/fluent_tools.rb
70
+ - lib/fluent_tools/cli.rb
71
+ - lib/fluent_tools/command_executor.rb
72
+ - lib/fluent_tools/utils.rb
73
+ - lib/fluent_tools/version.rb
74
+ homepage: https://github.com/Automattic/fluent-rust-tools
75
+ licenses:
76
+ - MPL-2.0
77
+ metadata:
78
+ allowed_push_host: https://rubygems.org
79
+ homepage_uri: https://github.com/Automattic/fluent-rust-tools
80
+ source_code_uri: https://github.com/Automattic/fluent-rust-tools
81
+ changelog_uri: https://github.com/Automattic/fluent-rust-tools/blob/main/CHANGELOG.md
82
+ post_install_message: |
83
+ This fluent-tools gem will try to use a pre-built binary for your platform.
84
+ If unavailable, it will compile the Rust binary during installation.
85
+
86
+ If compilation is needed, make sure you have Rust installed: https://rustup.rs/
87
+ rdoc_options: []
88
+ require_paths:
89
+ - lib
90
+ required_ruby_version: !ruby/object:Gem::Requirement
91
+ requirements:
92
+ - - ">="
93
+ - !ruby/object:Gem::Version
94
+ version: 3.2.2
95
+ required_rubygems_version: !ruby/object:Gem::Requirement
96
+ requirements:
97
+ - - ">="
98
+ - !ruby/object:Gem::Version
99
+ version: '0'
100
+ requirements: []
101
+ rubygems_version: 3.4.10
102
+ signing_key:
103
+ specification_version: 4
104
+ summary: Convert between Fluent and other formats (Android XML, GNU gettext PO)
105
+ test_files: []