ruby_native 0.0.1 → 0.0.3

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b95fa93f1758ce5b7425891875f07a5c8ec5f97f04cb7dc8714f945181aee1e4
4
- data.tar.gz: 2d7648eed1498803d7e7b7a49f77e8e2613c3a54b583091ab236575acfd45d22
3
+ metadata.gz: ec3f67cb02a265d7b8cd8a566e138408c9414f8ee79a16888b419a6a36c5c8f6
4
+ data.tar.gz: 72b1f835e77f85b6ab829181a319612abef5dd714a45f4541492373b528257c7
5
5
  SHA512:
6
- metadata.gz: 7458f250f336e7fb332bf1dda557a82117eb9bbc67d1eb581cc5656a677aa97ff2ab60a1c987c5a7aa6feae287345497d56dcbdf9c3733d33004ce413a491f11
7
- data.tar.gz: 4db4b2a5bf35a5d41ded39ce96946db3c94609bcc26a15463f8adac606dad45fa732517905fa681272207e8fc6cadf30cca362b69d3ad581ae5497ba66b9326b
6
+ metadata.gz: 7d95e30fb893f5d470102bbead726d381b8dd2298ab8f8ea1d3ffc26c6c1e41718b17cd78becef3cd30bc67a8063c72669860e688121d810ffe4b9ef820c3920
7
+ data.tar.gz: 38e2796256633182035d99cd52fe3ff943ad500601d515c03af7a196f54a38a8b05cd3c20f9f664c68be1e3509c42da285e2d628d3c42119bbb0f5d941c576f7
data/README.md CHANGED
@@ -5,20 +5,31 @@ A Rails engine that provides native detection, configuration, push device regist
5
5
  ## Installation
6
6
 
7
7
  ```ruby
8
- gem "ruby_native", path: "../../gem" # local development
8
+ gem "ruby_native"
9
9
  ```
10
10
 
11
- Then mount the engine in `config/routes.rb`:
11
+ The engine auto-mounts at `/native`. No route configuration needed.
12
12
 
13
- ```ruby
14
- Rails.application.routes.draw do
15
- mount RubyNative::Engine => "/native"
16
- end
13
+ ## Getting started
14
+
15
+ Run the install generator to create your config file:
16
+
17
+ ```bash
18
+ rails generate ruby_native:install
17
19
  ```
18
20
 
21
+ This creates `config/ruby_native.yml` with sensible defaults. If you have a `.claude/` directory, it also adds `.claude/ruby_native.md` with AI-assisted setup instructions. Follow the printed instructions to:
22
+
23
+ 1. Edit the config with your app name, colors, and tabs
24
+ 2. Add `<%= stylesheet_link_tag :ruby_native %>` to your layout `<head>`
25
+ 3. Add `<%= native_tabs_tag %>` to your layout `<body>`
26
+ 4. Run `ruby_native preview` to see it on your phone
27
+
28
+ Using Claude Code? Open it in your project and ask "what do I need to do next?" for guided setup.
29
+
19
30
  ## Configuration
20
31
 
21
- Create `config/ruby_native.yml`:
32
+ Edit `config/ruby_native.yml`:
22
33
 
23
34
  ```yaml
24
35
  app:
@@ -26,7 +37,6 @@ app:
26
37
  appearance:
27
38
  tint_color: "#4F46E5"
28
39
  background_color: "#FFFFFF"
29
- status_bar: dark
30
40
  status_bar_color: "#FFFFFF"
31
41
  tabs:
32
42
  - title: Home
@@ -37,6 +47,34 @@ tabs:
37
47
  icon: person
38
48
  ```
39
49
 
50
+ Color fields accept a plain hex string or an object with `light` and `dark` keys for dark mode:
51
+
52
+ ```yaml
53
+ background_color:
54
+ light: "#FFFFFF"
55
+ dark: "#1C1C1E"
56
+ ```
57
+
58
+ ## Preview
59
+
60
+ Preview your app on a real device without deploying. This starts a Cloudflare tunnel and displays a QR code for the companion app to scan.
61
+
62
+ ```bash
63
+ ruby_native preview
64
+ ```
65
+
66
+ Options:
67
+
68
+ - `--port 3001` - specify the local server port (defaults to 3000)
69
+
70
+ Requires `cloudflared`. Install with:
71
+
72
+ ```bash
73
+ brew install cloudflare/cloudflare/cloudflared
74
+ ```
75
+
76
+ The companion app persists the scanned URL across launches. Long-press the app icon and tap "Switch website" to scan a new server.
77
+
40
78
  ## Endpoints
41
79
 
42
80
  - `GET /native/config` - returns the YAML config as JSON
@@ -1,6 +1,7 @@
1
1
  module RubyNative
2
2
  class ConfigController < ::ActionController::Base
3
3
  def show
4
+ RubyNative.load_config if Rails.env.local?
4
5
  render json: RubyNative.config
5
6
  end
6
7
  end
data/exe/ruby_native ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+ require "ruby_native/cli"
3
+ RubyNative::CLI.start(ARGV)
@@ -0,0 +1,48 @@
1
+ module RubyNative
2
+ module Generators
3
+ class InstallGenerator < Rails::Generators::Base
4
+ source_root File.expand_path("templates", __dir__)
5
+
6
+ desc "Creates a Ruby Native config file at config/ruby_native.yml"
7
+
8
+ def copy_config
9
+ template "ruby_native.yml", "config/ruby_native.yml"
10
+ end
11
+
12
+ def add_allowed_host
13
+ host_line = ' config.hosts << ".trycloudflare.com"'
14
+ dev_config = "config/environments/development.rb"
15
+
16
+ return unless File.exist?(File.join(destination_root, dev_config))
17
+ return if File.read(File.join(destination_root, dev_config)).include?("trycloudflare")
18
+
19
+ environment(host_line, env: "development")
20
+ say " Added .trycloudflare.com to allowed hosts in development.rb", :green
21
+ end
22
+
23
+ def copy_claude_instructions
24
+ return unless File.directory?(destination_root.join(".claude"))
25
+ template "CLAUDE.md", ".claude/ruby_native.md"
26
+ end
27
+
28
+ def print_next_steps
29
+ say ""
30
+ say "Ruby Native installed! Next steps:", :green
31
+ say ""
32
+ say " 1. Edit config/ruby_native.yml with your app name, colors, and tabs"
33
+ say " 2. Add to your layout <head>:"
34
+ say " <%= stylesheet_link_tag :ruby_native %>"
35
+ say " 3. Add to your layout <body>:"
36
+ say " <%= native_tabs_tag %>"
37
+ say " 4. Preview on your device:"
38
+ say " ruby_native preview"
39
+ say ""
40
+ if File.directory?(destination_root.join(".claude"))
41
+ say " Tip: .claude/ruby_native.md was added with setup instructions."
42
+ say " Open Claude Code and ask \"what do I need to do next?\" for guided help."
43
+ say ""
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,154 @@
1
+ # Ruby Native
2
+
3
+ Turn your Rails app into an iOS app. Any frontend framework. No Xcode required.
4
+
5
+ ## Quick start
6
+
7
+ 1. Add the gem to your Gemfile and bundle:
8
+
9
+ ```ruby
10
+ gem "ruby_native"
11
+ ```
12
+
13
+ 2. Run the install generator:
14
+
15
+ ```bash
16
+ rails generate ruby_native:install
17
+ ```
18
+
19
+ 3. Edit `config/ruby_native.yml` with your app name, colors, and tabs.
20
+
21
+ 4. Add to your layout `<head>`:
22
+
23
+ ```erb
24
+ <%= stylesheet_link_tag :ruby_native %>
25
+ ```
26
+
27
+ 5. Add to your layout `<body>`:
28
+
29
+ ```erb
30
+ <%= native_tabs_tag %>
31
+ ```
32
+
33
+ 6. Preview on your phone:
34
+
35
+ ```bash
36
+ ruby_native preview
37
+ ```
38
+
39
+ Scan the QR code with the Ruby Native Preview app from the App Store.
40
+
41
+ ## Configuration
42
+
43
+ `config/ruby_native.yml` controls the native shell. Changes are picked up without restarting the server in development.
44
+
45
+ ```yaml
46
+ app:
47
+ name: My App
48
+
49
+ appearance:
50
+ tint_color: "#007AFF"
51
+ background_color: "#FFFFFF"
52
+ status_bar_color: "#F8F9FA"
53
+
54
+ tabs:
55
+ - title: Home
56
+ path: /
57
+ icon: house
58
+ - title: Profile
59
+ path: /profile
60
+ icon: person
61
+ ```
62
+
63
+ Icons use SF Symbols names (e.g., `house`, `person`, `envelope`, `gear`).
64
+
65
+ ### Dark mode
66
+
67
+ Color fields accept a plain hex string or an object with `light` and `dark` keys:
68
+
69
+ ```yaml
70
+ background_color:
71
+ light: "#FFFFFF"
72
+ dark: "#212529"
73
+ status_bar_color:
74
+ light: "#F8F9FA"
75
+ dark: "#2B3035"
76
+ ```
77
+
78
+ Match these to your CSS framework's dark mode colors. For Bootstrap, `#212529` is `--bs-body-bg` and `#2B3035` is `--bs-tertiary-bg` in dark mode.
79
+
80
+ ## View helpers
81
+
82
+ Use these in your layouts and views:
83
+
84
+ - `native_app?` returns true when the request comes from a Ruby Native app. Use it to hide web-only UI like navbars.
85
+ - `native_tabs_tag` renders a signal element that tells the app to show the tab bar. Only include it on pages where tabs should appear.
86
+ - `native_form_tag` marks the page as a form. The app uses this to skip form pages when navigating back.
87
+ - `native_push_tag` requests push notification permission from the user.
88
+
89
+ Signal elements are hidden `<div>` tags. Place them in the `<body>`, not the `<head>`.
90
+
91
+ ### Example layout
92
+
93
+ ```erb
94
+ <body>
95
+ <%= native_tabs_tag if user_signed_in? %>
96
+ <%= render "navbar" unless native_app? %>
97
+ <%= yield %>
98
+ </body>
99
+ ```
100
+
101
+ ## Preview
102
+
103
+ `ruby_native preview` starts a Cloudflare tunnel and displays a QR code. Requires `cloudflared`:
104
+
105
+ ```bash
106
+ brew install cloudflare/cloudflare/cloudflared
107
+ ```
108
+
109
+ Options:
110
+ - `--port 3001` to specify the local server port (defaults to 3000)
111
+
112
+ The install generator adds `.trycloudflare.com` to `config.hosts` in `development.rb` automatically. If you skipped the generator, add it manually:
113
+
114
+ ```ruby
115
+ # config/environments/development.rb
116
+ config.hosts << ".trycloudflare.com"
117
+ ```
118
+
119
+ The Preview app remembers the scanned URL. Long-press the app icon and tap "Switch website" to scan a new server.
120
+
121
+ ## Endpoints
122
+
123
+ The gem auto-mounts at `/native`. No route configuration needed.
124
+
125
+ - `GET /native/config.json` returns the YAML config as JSON
126
+ - `POST /native/push/devices` registers a push notification device token
127
+
128
+ ## Common tasks
129
+
130
+ ### Hide web navigation in the native app
131
+
132
+ ```erb
133
+ <%= render "navbar" unless native_app? %>
134
+ ```
135
+
136
+ ### Show tabs only for signed-in users
137
+
138
+ ```erb
139
+ <%= native_tabs_tag if user_signed_in? %>
140
+ ```
141
+
142
+ ### Add a native back button
143
+
144
+ Add an element with the `native-back-button` class. The gem's stylesheet handles showing it only when there's history to go back to.
145
+
146
+ ```erb
147
+ <%= stylesheet_link_tag :ruby_native %>
148
+ ```
149
+
150
+ ```erb
151
+ <button class="native-back-button" onclick="webkit.messageHandlers.rubyNative.postMessage({action: 'back'})">
152
+ Back
153
+ </button>
154
+ ```
@@ -0,0 +1,22 @@
1
+ app:
2
+ name: My App
3
+
4
+ appearance:
5
+ tint_color: "#007AFF"
6
+ background_color: "#FFFFFF"
7
+ status_bar_color: "#F8F9FA"
8
+ # Dark mode example (replace the plain strings above):
9
+ # background_color:
10
+ # light: "#FFFFFF"
11
+ # dark: "#1C1C1E"
12
+ # status_bar_color:
13
+ # light: "#F8F9FA"
14
+ # dark: "#1C1C1E"
15
+
16
+ tabs:
17
+ - title: Home
18
+ path: /
19
+ icon: house
20
+ - title: Profile
21
+ path: /profile
22
+ icon: person
@@ -0,0 +1,136 @@
1
+ require "open3"
2
+
3
+ module RubyNative
4
+ class CLI
5
+ class Preview
6
+ TUNNEL_URL_PATTERN = %r{https://[a-z0-9-]+\.trycloudflare\.com}
7
+
8
+ BLACK_BG = "\033[48;2;0;0;0m"
9
+ WHITE_BG = "\033[48;2;255;255;255m"
10
+ BLACK_FG = "\033[38;2;0;0;0m"
11
+ WHITE_FG = "\033[38;2;255;255;255m"
12
+ RESET = "\033[0m"
13
+
14
+ def initialize(argv)
15
+ @port = parse_port(argv)
16
+ end
17
+
18
+ def run
19
+ check_cloudflared!
20
+ start_tunnel
21
+ end
22
+
23
+ private
24
+
25
+ def parse_port(argv)
26
+ index = argv.index("--port")
27
+ if index
28
+ argv[index + 1]&.to_i || 3000
29
+ else
30
+ 3000
31
+ end
32
+ end
33
+
34
+ def check_cloudflared!
35
+ unless system("which cloudflared > /dev/null 2>&1")
36
+ puts "cloudflared is not installed."
37
+ puts ""
38
+ puts "Install it with Homebrew:"
39
+ puts " brew install cloudflare/cloudflare/cloudflared"
40
+ puts ""
41
+ puts "Or see: https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/downloads/"
42
+ exit 1
43
+ end
44
+ end
45
+
46
+ def start_tunnel
47
+ puts "Starting tunnel to http://localhost:#{@port}..."
48
+
49
+ stdin, stdout_err, wait_thread = Open3.popen2e(
50
+ "cloudflared", "tunnel", "--url", "http://localhost:#{@port}"
51
+ )
52
+ stdin.close
53
+
54
+ @tunnel_pid = wait_thread.pid
55
+ trap_interrupt
56
+
57
+ tunnel_url = nil
58
+
59
+ stdout_err.each_line do |line|
60
+ if line =~ TUNNEL_URL_PATTERN
61
+ tunnel_url = line[TUNNEL_URL_PATTERN]
62
+ display_qr(tunnel_url)
63
+ end
64
+ end
65
+ rescue Interrupt
66
+ # Handled by trap
67
+ ensure
68
+ kill_tunnel
69
+ end
70
+
71
+ def display_qr(url)
72
+ require "rqrcode"
73
+
74
+ qr = RQRCode::QRCode.new(url)
75
+ modules = qr.modules
76
+
77
+ print "\033[2J\033[H" # Clear terminal
78
+
79
+ # Use Unicode half-block characters to render two QR rows per
80
+ # terminal row, cutting the height in half for square proportions.
81
+ quiet = 1
82
+ size = modules.length
83
+ total = size + quiet * 2
84
+
85
+ lines = []
86
+
87
+ (0...total).step(2) do |r|
88
+ line = ""
89
+ total.times do |c|
90
+ top = pixel_dark?(modules, r, c, quiet, size)
91
+ bottom = pixel_dark?(modules, r + 1, c, quiet, size)
92
+
93
+ if top && bottom
94
+ line << "#{BLACK_BG} #{RESET}"
95
+ elsif top
96
+ line << "#{BLACK_BG}#{WHITE_FG}\u2584#{RESET}"
97
+ elsif bottom
98
+ line << "#{WHITE_BG}#{BLACK_FG}\u2584#{RESET}"
99
+ else
100
+ line << "#{WHITE_BG} #{RESET}"
101
+ end
102
+ end
103
+ lines << line
104
+ end
105
+
106
+ puts lines.join("\n")
107
+ puts ""
108
+ puts url
109
+ puts ""
110
+ puts "Scan with the Ruby Native preview app."
111
+ puts "Press Ctrl+C to stop."
112
+ end
113
+
114
+ def trap_interrupt
115
+ Signal.trap("INT") do
116
+ kill_tunnel
117
+ exit 0
118
+ end
119
+ end
120
+
121
+ def kill_tunnel
122
+ return unless @tunnel_pid
123
+ Process.kill("TERM", @tunnel_pid)
124
+ Process.wait(@tunnel_pid)
125
+ rescue Errno::ESRCH, Errno::ECHILD
126
+ # Process already exited.
127
+ end
128
+
129
+ def pixel_dark?(modules, row, col, quiet, size)
130
+ r = row - quiet
131
+ c = col - quiet
132
+ r >= 0 && r < size && c >= 0 && c < size && modules[r][c]
133
+ end
134
+ end
135
+ end
136
+ end
@@ -0,0 +1,15 @@
1
+ require "ruby_native/cli/preview"
2
+
3
+ module RubyNative
4
+ class CLI
5
+ def self.start(argv)
6
+ command = argv.shift
7
+ case command
8
+ when "preview"
9
+ RubyNative::CLI::Preview.new(argv).run
10
+ else
11
+ puts "Usage: ruby_native preview [--port PORT]"
12
+ end
13
+ end
14
+ end
15
+ end
@@ -1,3 +1,3 @@
1
1
  module RubyNative
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.3"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby_native
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Joe Masilotti
8
8
  autorequire:
9
- bindir: bin
9
+ bindir: exe
10
10
  cert_chain: []
11
- date: 2026-02-11 00:00:00.000000000 Z
11
+ date: 2026-02-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -24,11 +24,26 @@ dependencies:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: '7.1'
27
- description: A Rails engine providing native detection, configuration, push device
28
- registration, and view helpers for Ruby Native iOS and Android apps.
27
+ - !ruby/object:Gem::Dependency
28
+ name: rqrcode
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '3.0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '3.0'
41
+ description: Turn your existing Rails app into a native iOS and Android app with Ruby
42
+ Native.
29
43
  email:
30
44
  - joe@masilotti.com
31
- executables: []
45
+ executables:
46
+ - ruby_native
32
47
  extensions: []
33
48
  extra_rdoc_files: []
34
49
  files:
@@ -38,7 +53,13 @@ files:
38
53
  - app/controllers/ruby_native/config_controller.rb
39
54
  - app/controllers/ruby_native/push/devices_controller.rb
40
55
  - config/routes.rb
56
+ - exe/ruby_native
57
+ - lib/generators/ruby_native/install_generator.rb
58
+ - lib/generators/ruby_native/templates/CLAUDE.md
59
+ - lib/generators/ruby_native/templates/ruby_native.yml
41
60
  - lib/ruby_native.rb
61
+ - lib/ruby_native/cli.rb
62
+ - lib/ruby_native/cli/preview.rb
42
63
  - lib/ruby_native/engine.rb
43
64
  - lib/ruby_native/helper.rb
44
65
  - lib/ruby_native/native_detection.rb
@@ -65,5 +86,5 @@ requirements: []
65
86
  rubygems_version: 3.0.3.1
66
87
  signing_key:
67
88
  specification_version: 4
68
- summary: Native bridge helpers for Ruby Native apps.
89
+ summary: Turn your existing Rails app into a native iOS and Android app.
69
90
  test_files: []