flutter_on_rails 0.0.1.alpha

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: 94f09e0fe0bff2d6a62548366d061cb69c9afa207b3c539f8b0fcb0248c5abff
4
+ data.tar.gz: 2fd112d4df8052bf90dabd165befff689b63366f66c45bc318c06c6bebf7884d
5
+ SHA512:
6
+ metadata.gz: 90326bf30a94d939487f73bd459ab16d96b11f81259c7d47bafe6579a8c8b5b7f90b57034f5f2d7cbdc670231b00c07a5635eed93efbe1aa8e8019d4448cb582
7
+ data.tar.gz: 97f8a3c74f4fa4b416a4ccb4dff8725dfb15ae4e3615ebdf6492c832d44bac555e61fc408e174a06f9333801924f10add7526939a27067afed22d7711e6215c5
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Your Name
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,46 @@
1
+ # Flutter on Rails CLI
2
+
3
+ A Ruby CLI tool for managing Flutter applications with ease.
4
+
5
+ ## Installation
6
+
7
+ 1. Make sure you have Ruby installed
8
+ 2. Install dependencies:
9
+
10
+ ```bash
11
+ bundle install
12
+ ```
13
+
14
+ ## Usage
15
+
16
+ ### Create a new Flutter app
17
+
18
+ ```bash
19
+ flutter_on_rails create or frails create
20
+ ```
21
+
22
+ This will:
23
+
24
+ - Create a new Flutter application
25
+ - Optionally add dependencies
26
+ - Optionally configure splash screen
27
+
28
+ ### Build Flutter app
29
+
30
+ ```bash
31
+ flutter_on_rails build or frails build
32
+ ```
33
+
34
+ This will:
35
+
36
+ - Let you choose the platform (android/ios/web/windows/macos/linux)
37
+ - Let you choose build type (debug/release)
38
+ - Build the application for the selected platform
39
+
40
+ ## Features
41
+
42
+ - Colorful CLI interface
43
+ - Interactive prompts
44
+ - Splash screen configuration
45
+ - Dependency management
46
+ - Multi-platform build support
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require_relative '../lib/flutter_cli'
data/bin/frails ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env ruby
2
+ require_relative '../lib/flutter_cli'
@@ -0,0 +1,417 @@
1
+ require 'thor'
2
+ require 'colorize'
3
+ require 'tty-prompt'
4
+ require 'tty-spinner'
5
+ require 'yaml'
6
+
7
+ class FlutterCLI < Thor
8
+ # Set package name for both 'flutter_on_rails' and 'frails'
9
+ package_name "Flutter on Rails CLI"
10
+
11
+ # Define exit_on_failure? to maintain Thor's exit with status 0 on errors
12
+ def self.exit_on_failure?
13
+ false
14
+ end
15
+
16
+ # Commands
17
+ map %w[n new] => :create
18
+ map "r" => :run_app
19
+ map "b" => :build
20
+ map "a" => :apply
21
+ map "i" => :install
22
+
23
+ desc "apply", "Apply configurations (TYPE=splash_screen or icon_launcher)"
24
+ def apply(type)
25
+ case type
26
+ when "splash_screen"
27
+ spinner = TTY::Spinner.new("[:spinner] Generating splash screen ...", format: :dots)
28
+ spinner.auto_spin
29
+ system("dart run flutter_native_splash:create > /dev/null 2>&1")
30
+ spinner.success("Splash screen generated!".colorize(:green))
31
+ when "icon_launcher"
32
+ spinner = TTY::Spinner.new("[:spinner] Generating launcher icons ...", format: :dots)
33
+ spinner.auto_spin
34
+ system("dart run flutter_launcher_icons > /dev/null 2>&1")
35
+ spinner.success("Launcher icons generated!".colorize(:green))
36
+ else
37
+ puts "Invalid type. Use 'splash_screen' or 'icon_launcher'".colorize(:red)
38
+ end
39
+ end
40
+
41
+ desc "run", "Run the Flutter app in debug mode"
42
+ def run_app
43
+ prompt = TTY::Prompt.new
44
+ # Show spinner while getting devices
45
+ spinner = TTY::Spinner.new("[:spinner] Detecting devices...", format: :dots)
46
+ spinner.auto_spin
47
+
48
+ # Get list of available devices using --machine flag for faster parsing
49
+ devices_output = `flutter devices --machine 2>/dev/null`
50
+ devices = []
51
+
52
+ begin
53
+ require 'json'
54
+ JSON.parse(devices_output).each do |device|
55
+ devices << {
56
+ name: device['name'],
57
+ id: device['id'],
58
+ platform: device['targetPlatform'] || device['platformType']
59
+ }
60
+ end
61
+ rescue JSON::ParserError
62
+ # Fallback to regular output parsing if JSON fails
63
+ devices_output = `flutter devices`
64
+ devices_output.each_line do |line|
65
+ next if line.strip.empty? || line.include?("Found") || line.include?("No devices")
66
+ if match = line.match(/^([^•]+)•([^•]+)•(.+)$/)
67
+ name, id, platform = match.captures.map(&:strip)
68
+ devices << {
69
+ name: name,
70
+ id: id,
71
+ platform: platform
72
+ }
73
+ end
74
+ end
75
+ end
76
+
77
+ spinner.stop
78
+
79
+ if devices.empty?
80
+ puts "No devices found. Please connect a device or start a simulator.".colorize(:red)
81
+ return
82
+ end
83
+
84
+ # No need to show device count, just show the selection prompt
85
+
86
+ # Let user choose device
87
+ choices = devices.map do |d|
88
+ # Get device type from platform and name
89
+ device_type = case
90
+ when d[:platform].downcase.include?('ios') then :ios
91
+ when d[:platform].downcase.include?('android') then :android
92
+ when d[:platform].downcase.include?('chrome') || d[:platform].downcase.include?('web') then :web
93
+ when d[:platform].downcase.include?('darwin') || d[:name].downcase.include?('mac') then :macos
94
+ when d[:platform].downcase.include?('windows') then :windows
95
+ when d[:platform].downcase.include?('linux') then :linux
96
+ else :unknown
97
+ end
98
+
99
+ # Determine device type icon and platform color
100
+ icon, platform_color = case device_type
101
+ when :ios
102
+ if d[:name].downcase.include?('simulator')
103
+ ["📱", :light_blue] # iOS simulator
104
+ else
105
+ ["📲", :light_blue] # Physical iOS device
106
+ end
107
+ when :android
108
+ if d[:name].downcase.include?('emulator')
109
+ ["📱", :green] # Android emulator
110
+ else
111
+ ["🤖", :green] # Physical Android device
112
+ end
113
+ when :macos
114
+ if d[:name].downcase.include?('ipad')
115
+ ["💻", :magenta] # Mac for iPad
116
+ else
117
+ ["🖥", :magenta] # macOS desktop
118
+ end
119
+ when :windows
120
+ ["🪟", :blue] # Windows desktop
121
+ when :linux
122
+ ["🐧", :red] # Linux desktop
123
+ when :web
124
+ if d[:platform].downcase.include?('chrome')
125
+ ["🌐", :yellow] # Chrome browser
126
+ else
127
+ ["🌎", :yellow] # Other web platform
128
+ end
129
+ else
130
+ ["💻", :white] # Unknown platform
131
+ end
132
+
133
+ # Clean up and format the device name
134
+ device_name = case device_type
135
+ when :macos
136
+ if d[:name].downcase.include?('ipad')
137
+ 'Mac (iPad)'
138
+ else
139
+ ' macOS'
140
+ end
141
+ else
142
+ d[:name].gsub(/\s+\([^)]*\)/, '') # Remove parenthetical descriptions only
143
+ end
144
+
145
+ # Format the device info with consistent spacing
146
+ icon_part = "#{icon}".ljust(6) # Icon with padding
147
+ name_part = device_name.ljust(22) # Name with padding
148
+ platform_part = d[:platform].colorize(platform_color) # Platform name
149
+
150
+ {
151
+ name: "#{icon_part}#{name_part}#{platform_part}", # Using only padding for alignment
152
+ value: d[:id],
153
+ disabled: d[:platform].include?("unavailable") ? "Device unavailable" : false
154
+ }
155
+ end
156
+
157
+ begin
158
+ # Configure prompt to be more stable
159
+ prompt.on(:keypress) {}
160
+ device = prompt.select(
161
+ "Select a device to run on:".colorize(:cyan),
162
+ choices,
163
+ cycle: true,
164
+ per_page: devices.length,
165
+ interrupt: :exit # Exit cleanly on Ctrl+C during selection
166
+ )
167
+
168
+ spinner = TTY::Spinner.new("[:spinner] Starting app on selected device ...", format: :dots)
169
+ spinner.auto_spin
170
+
171
+ # Handle Ctrl+C gracefully for the Flutter process
172
+ begin
173
+ pid = spawn("flutter run -d #{device}")
174
+ Process.wait(pid)
175
+ rescue Interrupt
176
+ # Stop the spinner and clear the line
177
+ spinner.stop
178
+ print "\n" # Move to new line
179
+ puts "Stopping Flutter app...".colorize(:yellow)
180
+ # Kill the Flutter process group
181
+ Process.kill('-INT', pid) rescue nil
182
+ Process.wait(pid) rescue nil
183
+ exit(0)
184
+ end
185
+
186
+ spinner.success("App started in debug mode!".colorize(:green))
187
+ rescue TTY::Reader::InputInterrupt
188
+ # Handle Ctrl+C during device selection
189
+ puts "\n\nInterrupted.".colorize(:yellow)
190
+ exit(0)
191
+ rescue StandardError => e
192
+ # Handle any other errors gracefully
193
+ puts "\n\nError: #{e.message}".colorize(:red)
194
+ exit(1)
195
+ end
196
+ end
197
+
198
+ desc "build [PLATFORM]", "Build Flutter on Rails app for different platforms"
199
+ def build(platform = nil)
200
+ prompt = TTY::Prompt.new
201
+
202
+ platform ||= prompt.select("Choose platform to build for:".colorize(:cyan), [
203
+ "android",
204
+ "ios",
205
+ "windows",
206
+ "macos",
207
+ "linux"
208
+ ])
209
+
210
+ spinner = TTY::Spinner.new("[:spinner] Building #{platform} release ...", format: :dots)
211
+ spinner.auto_spin
212
+ system("flutter build #{platform} --release")
213
+ spinner.success("#{platform.capitalize} release build completed!".colorize(:green))
214
+ end
215
+
216
+ desc "create", "Create a new Flutter on Rails application"
217
+ def create
218
+ prompt = TTY::Prompt.new
219
+ spinner = TTY::Spinner.new("[:spinner] Creating Flutter on Rails app ...", format: :dots)
220
+
221
+ app_name = prompt.ask("What's your Flutter on Rails app name?".colorize(:cyan))
222
+ return puts "App name is required!".colorize(:red) unless app_name
223
+
224
+ spinner.auto_spin
225
+ system("flutter create #{app_name} > /dev/null 2>&1")
226
+ spinner.success("Flutter on Rails app created!".colorize(:green))
227
+
228
+ # Add dependencies first
229
+ add_dependencies(app_name)
230
+
231
+ # Replace main.dart content
232
+ replace_main_dart(app_name)
233
+
234
+ # Add configurations before installing dependencies
235
+ configure_splash_screen(app_name)
236
+ configure_launcher_icons(app_name)
237
+
238
+ # Clean up and normalize pubspec.yaml
239
+ normalize_pubspec_yaml(app_name)
240
+
241
+ # Install dependencies after configurations are added
242
+ spinner = TTY::Spinner.new("[:spinner] Installing dependencies ...", format: :dots)
243
+ spinner.auto_spin
244
+ system("cd #{app_name} && flutter pub get > /dev/null 2>&1")
245
+ spinner.success("Dependencies installed!".colorize(:green))
246
+
247
+ # Copy assets folder from CLI to new project
248
+ spinner = TTY::Spinner.new("[:spinner] Copying assets folder ...", format: :dots)
249
+ spinner.auto_spin
250
+ cli_root = File.expand_path(File.dirname(__FILE__) + "/../")
251
+ system("cp -r #{cli_root}/assets #{app_name}/")
252
+ spinner.success("Assets folder copied!".colorize(:green))
253
+
254
+ puts "\n✨ Your Flutter on Rails app is ready! ✨".colorize(:green)
255
+ puts "\nNext steps:".colorize(:yellow)
256
+ puts "1. cd #{app_name}".colorize(:cyan)
257
+ puts "2. frails run".colorize(:cyan)
258
+
259
+ puts "\nNote:".colorize(:yellow)
260
+ puts "- To update splash screen: frails apply splash_screen".colorize(:cyan)
261
+ puts "- To update app icons: frails apply icon_launcher".colorize(:cyan)
262
+ end
263
+
264
+ private
265
+
266
+ def replace_main_dart(app_name)
267
+ main_dart_content = <<~DART
268
+ import 'package:flutter/material.dart';
269
+ import 'package:flutter_on_rails/flutter_on_rails.dart';
270
+
271
+ void main() async {
272
+ WidgetsFlutterBinding.ensureInitialized();
273
+ await init();
274
+ runApp(MaterialApp(home: MainScreen()));
275
+ }
276
+ DART
277
+
278
+ File.write("#{app_name}/lib/main.dart", main_dart_content)
279
+ system("rm -rf #{app_name}/test")
280
+ end
281
+
282
+ def normalize_pubspec_yaml(app_name)
283
+ spinner = TTY::Spinner.new("[:spinner] Normalizing pubspec.yaml ...", format: :dots)
284
+ spinner.auto_spin
285
+
286
+ pubspec_path = "#{app_name}/pubspec.yaml"
287
+ temp_config_path = "#{app_name}/.temp_config.yaml"
288
+
289
+ # Write our configurations to a temporary file
290
+ config = {}
291
+ config['flutter_native_splash'] = @splash_screen_config if @splash_screen_config
292
+ config['flutter_launcher_icons'] = @launcher_icons_config if @launcher_icons_config
293
+
294
+ # Only write and append if we have configurations to add
295
+ unless config.empty?
296
+ File.write(temp_config_path, config.to_yaml.sub(/^---\n/, ''))
297
+ system("cat #{temp_config_path} >> #{pubspec_path} && rm #{temp_config_path}")
298
+ end
299
+
300
+ spinner.success("pubspec.yaml normalized".colorize(:green))
301
+ end
302
+
303
+
304
+ def add_dependencies(app_name)
305
+ spinner = TTY::Spinner.new("[:spinner] Adding dependencies ...", format: :dots)
306
+
307
+ # Silently add Flutter on Rails
308
+ spinner.auto_spin
309
+ system("cd #{app_name} && flutter pub add flutter_on_rails > /dev/null 2>&1")
310
+ spinner.success("Added Flutter on Rails package".colorize(:green))
311
+
312
+ # Silently add flutter_launcher_icons as dev dependency
313
+ spinner.auto_spin
314
+ system("cd #{app_name} && flutter pub add -d flutter_launcher_icons:^0.14.3 > /dev/null 2>&1")
315
+ spinner.success("Added flutter_launcher_icons package".colorize(:green))
316
+
317
+ # Add flutter_native_splash dependency
318
+ spinner.auto_spin
319
+ system("cd #{app_name} && flutter pub add flutter_native_splash > /dev/null 2>&1")
320
+ spinner.success("Added flutter_native_splash".colorize(:green))
321
+ end
322
+
323
+ def configure_splash_screen(app_name)
324
+ spinner = TTY::Spinner.new("[:spinner] Configuring splash screen ...", format: :dots)
325
+ spinner.auto_spin
326
+
327
+ # Read and parse existing pubspec.yaml
328
+ pubspec_path = "#{app_name}/pubspec.yaml"
329
+ yaml_data = YAML.load_file(pubspec_path) || {}
330
+
331
+ # Check if configuration already exists
332
+ return if yaml_data['flutter_native_splash']
333
+
334
+ # Create assets directory structure
335
+ system("cd #{app_name} && mkdir -p assets")
336
+
337
+ # Add splash screen configuration
338
+ yaml_data['flutter_native_splash'] = {
339
+ 'color' => '#42a5f5',
340
+ 'image' => 'assets/splash.png',
341
+ 'branding' => 'assets/branding.png',
342
+ 'color_dark' => '#042a49',
343
+ 'image_dark' => 'assets/splash.png',
344
+ 'branding_dark' => 'assets/splash.png',
345
+ 'android_12' => {
346
+ 'image' => 'assets/splash.png',
347
+ 'icon_background_color' => '#42a5f5',
348
+ 'image_dark' => 'assets/splash.png',
349
+ 'icon_background_color_dark' => '#042a49'
350
+ },
351
+ 'android' => true,
352
+ 'ios' => true,
353
+ 'web' => false
354
+ }
355
+
356
+ # Add uses-material-design if not present
357
+ yaml_data['flutter'] ||= {}
358
+ yaml_data['flutter']['uses-material-design'] = true
359
+
360
+ # Save the configuration to be applied during normalization
361
+ @splash_screen_config = yaml_data['flutter_native_splash']
362
+ spinner.success("Splash screen configuration added!".colorize(:green))
363
+ end
364
+
365
+ def configure_launcher_icons(app_name)
366
+ spinner = TTY::Spinner.new("[:spinner] Configuring launcher icons ...", format: :dots)
367
+ spinner.auto_spin
368
+
369
+ # Read and parse existing pubspec.yaml
370
+ pubspec_path = "#{app_name}/pubspec.yaml"
371
+ yaml_data = YAML.load_file(pubspec_path) || {}
372
+
373
+ # Check if configuration already exists
374
+ return if yaml_data['flutter_launcher_icons']
375
+
376
+ # Create assets directory structure
377
+ system("cd #{app_name} && mkdir -p assets/icon")
378
+
379
+ # Add launcher icons configuration
380
+ yaml_data['flutter_launcher_icons'] = {
381
+ 'android' => 'launcher_icon',
382
+ 'ios' => true,
383
+ 'image_path' => 'assets/icon/logo.png',
384
+ 'min_sdk_android' => 21,
385
+ 'web' => {
386
+ 'generate' => true,
387
+ 'image_path' => 'assets/icon/logo.png',
388
+ 'background_color' => '#ffffff',
389
+ 'theme_color' => '#42a5f5'
390
+ },
391
+ 'windows' => {
392
+ 'generate' => true,
393
+ 'image_path' => 'assets/icon/logo.png',
394
+ 'icon_size' => 48
395
+ },
396
+ 'macos' => {
397
+ 'generate' => true,
398
+ 'image_path' => 'assets/icon/logo.png'
399
+ }
400
+ }
401
+
402
+ # Save the configuration to be applied during normalization
403
+ @launcher_icons_config = yaml_data['flutter_launcher_icons']
404
+ spinner.success("Launcher icons configuration added!".colorize(:green))
405
+ end
406
+
407
+ desc "install", "Install dependencies (flutter pub get)"
408
+ def install
409
+ spinner = TTY::Spinner.new("[:spinner] Installing dependencies ...", format: :dots)
410
+ spinner.auto_spin
411
+ system("flutter pub get > /dev/null 2>&1")
412
+ spinner.success("Dependencies installed!".colorize(:green))
413
+ end
414
+ end
415
+
416
+ # Allow both 'flutter_on_rails' and 'frails' commands
417
+ FlutterCLI.start(ARGV)
metadata ADDED
@@ -0,0 +1,161 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: flutter_on_rails
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1.alpha
5
+ platform: ruby
6
+ authors:
7
+ - Adam Moussa Ali
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: thor
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - "~>"
17
+ - !ruby/object:Gem::Version
18
+ version: '1.2'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - "~>"
24
+ - !ruby/object:Gem::Version
25
+ version: '1.2'
26
+ - !ruby/object:Gem::Dependency
27
+ name: colorize
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - "~>"
31
+ - !ruby/object:Gem::Version
32
+ version: '0.8'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '0.8'
40
+ - !ruby/object:Gem::Dependency
41
+ name: tty-prompt
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '0.23'
47
+ type: :runtime
48
+ prerelease: false
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: '0.23'
54
+ - !ruby/object:Gem::Dependency
55
+ name: tty-spinner
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: '0.9'
61
+ type: :runtime
62
+ prerelease: false
63
+ version_requirements: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: '0.9'
68
+ - !ruby/object:Gem::Dependency
69
+ name: yaml
70
+ requirement: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - "~>"
73
+ - !ruby/object:Gem::Version
74
+ version: '0.2'
75
+ type: :runtime
76
+ prerelease: false
77
+ version_requirements: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - "~>"
80
+ - !ruby/object:Gem::Version
81
+ version: '0.2'
82
+ - !ruby/object:Gem::Dependency
83
+ name: bundler
84
+ requirement: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - "~>"
87
+ - !ruby/object:Gem::Version
88
+ version: '2.0'
89
+ type: :development
90
+ prerelease: false
91
+ version_requirements: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - "~>"
94
+ - !ruby/object:Gem::Version
95
+ version: '2.0'
96
+ - !ruby/object:Gem::Dependency
97
+ name: rake
98
+ requirement: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - "~>"
101
+ - !ruby/object:Gem::Version
102
+ version: '13.0'
103
+ type: :development
104
+ prerelease: false
105
+ version_requirements: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - "~>"
108
+ - !ruby/object:Gem::Version
109
+ version: '13.0'
110
+ - !ruby/object:Gem::Dependency
111
+ name: rspec
112
+ requirement: !ruby/object:Gem::Requirement
113
+ requirements:
114
+ - - "~>"
115
+ - !ruby/object:Gem::Version
116
+ version: '3.0'
117
+ type: :development
118
+ prerelease: false
119
+ version_requirements: !ruby/object:Gem::Requirement
120
+ requirements:
121
+ - - "~>"
122
+ - !ruby/object:Gem::Version
123
+ version: '3.0'
124
+ description: Flutter on rails is the fastest way to bridge your web app with a Flutter-powered
125
+ for cross plateform mobile and desktop app with ease and minimal changes, maximum
126
+ freedom
127
+ email:
128
+ - adammusaaly@gmail.com
129
+ executables:
130
+ - flutter_on_rails
131
+ - frails
132
+ extensions: []
133
+ extra_rdoc_files: []
134
+ files:
135
+ - LICENSE
136
+ - README.md
137
+ - bin/flutter_on_rails
138
+ - bin/frails
139
+ - lib/flutter_cli.rb
140
+ homepage: https://github.com/AdamMusa/flutter_on_rails_cli
141
+ licenses:
142
+ - MIT
143
+ metadata: {}
144
+ rdoc_options: []
145
+ require_paths:
146
+ - lib
147
+ required_ruby_version: !ruby/object:Gem::Requirement
148
+ requirements:
149
+ - - ">="
150
+ - !ruby/object:Gem::Version
151
+ version: '3.0'
152
+ required_rubygems_version: !ruby/object:Gem::Requirement
153
+ requirements:
154
+ - - ">="
155
+ - !ruby/object:Gem::Version
156
+ version: '0'
157
+ requirements: []
158
+ rubygems_version: 3.6.8
159
+ specification_version: 4
160
+ summary: Flutter on Rails CLI
161
+ test_files: []