opal-vite 0.2.1 → 0.2.2

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: a747844bb38869490030ea9a7649cdd6f5b665cf2a60da55f3cc12f479aa556b
4
- data.tar.gz: 8e0de9d6b0b124f5ee0cb83cfd242199785c6a7ecdfb1f2e3ba0f7253bb5c663
3
+ metadata.gz: d02e4907cfae995a3c6496d788bf45bee0815c506be5685bc43caa417572f864
4
+ data.tar.gz: da33d83bca5ccc6eab82467d639c209911283a55bda3d9ce89d522639f1a2347
5
5
  SHA512:
6
- metadata.gz: d12af9028e4ca9537a4af9043a74fc3dd3cf043a0ed928ad199a5bf36625e2d3a0d392d7e45ac8f49832edb5c409664334ddb60571f794511156a4d50332644c
7
- data.tar.gz: '083ab7d7c102a315c9253491790014b6a5af41996bf81190d4a3f2c56bce9e503a3d204a0013866d2f9a956d311b9136bc2f5b86a317350d9f9585fe9ffc0299'
6
+ metadata.gz: bd7612a8e8b417ede04c9dcc8f71a7238e170f0d4d909e8fb44015211aa3ef59253e62cea003e5050d0d75052ea54da3f2c77fbf7211147987a566c97677b9cf
7
+ data.tar.gz: 0f325e40dd3785586ca1c39912602b4553fe2b8842d3d22504378c1887d9026b41ab85f70562c17025905879bacc44cf4295a7d3abf799a75137b459634dbdf6
@@ -1,5 +1,5 @@
1
1
  module Opal
2
2
  module Vite
3
- VERSION = "0.2.1"
3
+ VERSION = "0.2.2"
4
4
  end
5
5
  end
@@ -790,6 +790,488 @@ module OpalVite
790
790
  is_nan?(result) ? default_value : result
791
791
  end
792
792
 
793
+ # ===== JavaScript Property Access Methods =====
794
+
795
+ # Get a JavaScript property from the controller (this[name])
796
+ # @param name [Symbol, String] Property name
797
+ # @return [Native] Property value
798
+ def js_prop(name)
799
+ `this[#{name.to_s}]`
800
+ end
801
+
802
+ # Set a JavaScript property on the controller (this[name] = value)
803
+ # @param name [Symbol, String] Property name
804
+ # @param value [Object] Value to set
805
+ def js_set_prop(name, value)
806
+ `this[#{name.to_s}] = #{value}`
807
+ end
808
+
809
+ # Check if controller has a JavaScript property
810
+ # @param name [Symbol, String] Property name
811
+ # @return [Boolean] true if property exists and is truthy
812
+ def js_has_prop?(name)
813
+ `!!this[#{name.to_s}]`
814
+ end
815
+
816
+ # Call a JavaScript method on the controller (this[name](...args))
817
+ # @param name [Symbol, String] Method name
818
+ # @param args [Array] Arguments to pass
819
+ # @return [Native] Method return value
820
+ def js_call(name, *args)
821
+ if args.empty?
822
+ `this[#{name.to_s}]()`
823
+ else
824
+ native_args = args.map { |a| a.respond_to?(:to_n) ? a.to_n : a }
825
+ `this[#{name.to_s}].apply(this, #{native_args})`
826
+ end
827
+ end
828
+
829
+ # Call a method on a JavaScript object
830
+ # @param obj [Native] JavaScript object
831
+ # @param method [Symbol, String] Method name
832
+ # @param args [Array] Arguments to pass
833
+ # @return [Native] Method return value
834
+ def js_call_on(obj, method, *args)
835
+ if args.empty?
836
+ `#{obj}[#{method.to_s}]()`
837
+ else
838
+ native_args = args.map { |a| a.respond_to?(:to_n) ? a.to_n : a }
839
+ `#{obj}[#{method.to_s}].apply(#{obj}, #{native_args})`
840
+ end
841
+ end
842
+
843
+ # Get a property from a JavaScript object
844
+ # @param obj [Native] JavaScript object
845
+ # @param prop [Symbol, String] Property name
846
+ # @return [Native] Property value
847
+ def js_get(obj, prop)
848
+ `#{obj}[#{prop.to_s}]`
849
+ end
850
+
851
+ # Set a property on a JavaScript object
852
+ # @param obj [Native] JavaScript object
853
+ # @param prop [Symbol, String] Property name
854
+ # @param value [Object] Value to set
855
+ def js_set(obj, prop, value)
856
+ `#{obj}[#{prop.to_s}] = #{value}`
857
+ end
858
+
859
+ # ===== JSON Methods =====
860
+
861
+ # Parse JSON string to JavaScript object
862
+ # @param json_string [String] JSON string
863
+ # @return [Native] Parsed JavaScript object
864
+ def json_parse(json_string)
865
+ `JSON.parse(#{json_string})`
866
+ end
867
+
868
+ # Stringify JavaScript object to JSON
869
+ # @param obj [Object] Object to stringify
870
+ # @return [String] JSON string
871
+ def json_stringify(obj)
872
+ native_obj = obj.respond_to?(:to_n) ? obj.to_n : obj
873
+ `JSON.stringify(#{native_obj})`
874
+ end
875
+
876
+ # ===== Console Methods =====
877
+
878
+ # Log to console
879
+ # @param args [Array] Arguments to log
880
+ def console_log(*args)
881
+ `console.log.apply(console, #{args})`
882
+ end
883
+
884
+ # Log warning to console
885
+ # @param args [Array] Arguments to log
886
+ def console_warn(*args)
887
+ `console.warn.apply(console, #{args})`
888
+ end
889
+
890
+ # Log error to console
891
+ # @param args [Array] Arguments to log
892
+ def console_error(*args)
893
+ `console.error.apply(console, #{args})`
894
+ end
895
+
896
+ # ===== String Methods =====
897
+
898
+ # Get character at index from string
899
+ # @param str [String] JavaScript string
900
+ # @param index [Integer] Character index
901
+ # @return [String] Character at index
902
+ def js_string_char_at(str, index)
903
+ `#{str}.charAt(#{index})`
904
+ end
905
+
906
+ # Get substring
907
+ # @param str [String] JavaScript string
908
+ # @param start [Integer] Start index
909
+ # @param end_idx [Integer, nil] End index (optional)
910
+ # @return [String] Substring
911
+ def js_substring(str, start, end_idx = nil)
912
+ if end_idx
913
+ `#{str}.substring(#{start}, #{end_idx})`
914
+ else
915
+ `#{str}.substring(#{start})`
916
+ end
917
+ end
918
+
919
+ # Split string
920
+ # @param str [String] JavaScript string
921
+ # @param separator [String] Separator
922
+ # @return [Native] Array of substrings
923
+ def js_split(str, separator)
924
+ `#{str}.split(#{separator})`
925
+ end
926
+
927
+ # Trim whitespace from string
928
+ # @param str [String] JavaScript string
929
+ # @return [String] Trimmed string
930
+ def js_trim(str)
931
+ `#{str}.trim()`
932
+ end
933
+
934
+ # Check if string includes substring
935
+ # @param str [String] JavaScript string
936
+ # @param search [String] Substring to search for
937
+ # @return [Boolean] true if includes
938
+ def js_includes?(str, search)
939
+ `#{str}.includes(#{search})`
940
+ end
941
+
942
+ # ===== Comparison Methods =====
943
+
944
+ # Check strict equality (===) between two JavaScript values
945
+ # @param a [Native] First value
946
+ # @param b [Native] Second value
947
+ # @return [Boolean] true if strictly equal
948
+ def js_equals?(a, b)
949
+ `#{a} === #{b}`
950
+ end
951
+
952
+ # Check loose equality (==) between two JavaScript values
953
+ # @param a [Native] First value
954
+ # @param b [Native] Second value
955
+ # @return [Boolean] true if loosely equal
956
+ def js_loose_equals?(a, b)
957
+ `#{a} == #{b}`
958
+ end
959
+
960
+ # ===== Math Methods =====
961
+
962
+ # Generate random number between 0 and 1
963
+ # @return [Float] Random number
964
+ def js_random
965
+ `Math.random()`
966
+ end
967
+
968
+ # Get minimum of two numbers
969
+ # @param a [Number] First number
970
+ # @param b [Number] Second number
971
+ # @return [Number] Minimum value
972
+ def js_min(a, b)
973
+ `Math.min(#{a}, #{b})`
974
+ end
975
+
976
+ # Get maximum of two numbers
977
+ # @param a [Number] First number
978
+ # @param b [Number] Second number
979
+ # @return [Number] Maximum value
980
+ def js_max(a, b)
981
+ `Math.max(#{a}, #{b})`
982
+ end
983
+
984
+ # Get absolute value
985
+ # @param num [Number] Number
986
+ # @return [Number] Absolute value
987
+ def js_abs(num)
988
+ `Math.abs(#{num})`
989
+ end
990
+
991
+ # Round number
992
+ # @param num [Number] Number
993
+ # @return [Integer] Rounded number
994
+ def js_round(num)
995
+ `Math.round(#{num})`
996
+ end
997
+
998
+ # Ceiling of number
999
+ # @param num [Number] Number
1000
+ # @return [Integer] Ceiling value
1001
+ def js_ceil(num)
1002
+ `Math.ceil(#{num})`
1003
+ end
1004
+
1005
+ # Format number with fixed decimal places
1006
+ # @param num [Number] Number to format
1007
+ # @param digits [Integer] Number of decimal places
1008
+ # @return [String] Formatted number string
1009
+ def js_to_fixed(num, digits)
1010
+ `#{num}.toFixed(#{digits})`
1011
+ end
1012
+
1013
+ # Generate random integer between 0 and max (exclusive)
1014
+ # @param max [Integer] Maximum value (exclusive)
1015
+ # @return [Integer] Random integer
1016
+ def random_int(max)
1017
+ `Math.floor(Math.random() * #{max})`
1018
+ end
1019
+
1020
+ # Floor a number
1021
+ # @param num [Number] Number to floor
1022
+ # @return [Integer] Floored number
1023
+ def js_floor(num)
1024
+ `Math.floor(#{num})`
1025
+ end
1026
+
1027
+ # ===== Global Object Access =====
1028
+
1029
+ # Check if a global JavaScript object/class exists
1030
+ # @param name [String] Global name (e.g., 'Chart', 'React')
1031
+ # @return [Boolean] true if exists
1032
+ def js_global_exists?(name)
1033
+ `typeof window[#{name}] !== 'undefined'`
1034
+ end
1035
+
1036
+ # Get a global JavaScript object/class
1037
+ # @param name [String] Global name
1038
+ # @return [Native] Global object
1039
+ def js_global(name)
1040
+ `window[#{name}]`
1041
+ end
1042
+
1043
+ # Create new instance of a JavaScript class
1044
+ # @param klass [Native] JavaScript class/constructor
1045
+ # @param args [Array] Constructor arguments
1046
+ # @return [Native] New instance
1047
+ def js_new(klass, *args)
1048
+ if args.empty?
1049
+ `new klass()`
1050
+ else
1051
+ # Convert Ruby objects to native, pass JS objects as-is
1052
+ native_args = args.map { |a| `#{a} != null && typeof #{a}.$to_n === 'function' ? #{a}.$to_n() : #{a}` }
1053
+ # Use Reflect.construct for dynamic argument passing
1054
+ `Reflect.construct(#{klass}, #{native_args})`
1055
+ end
1056
+ end
1057
+
1058
+ # Define a JavaScript function on the controller (this[name] = function)
1059
+ # @param name [Symbol, String] Function name
1060
+ # @yield Block that becomes the function body
1061
+ def js_define_method(name, &block)
1062
+ `this[#{name.to_s}] = #{block}`
1063
+ end
1064
+
1065
+ # Define a JavaScript function on an object (obj[name] = function)
1066
+ # @param obj [Native] JavaScript object
1067
+ # @param name [Symbol, String] Function name
1068
+ # @yield Block that becomes the function body
1069
+ def js_define_method_on(obj, name, &block)
1070
+ `#{obj}[#{name.to_s}] = #{block}`
1071
+ end
1072
+
1073
+ # ===== Array Methods =====
1074
+
1075
+ # Get array length
1076
+ # @param arr [Native] JavaScript array
1077
+ # @return [Integer] Array length
1078
+ def js_length(arr)
1079
+ `#{arr}.length`
1080
+ end
1081
+
1082
+ # Map over array with block
1083
+ # @param arr [Native] JavaScript array
1084
+ # @yield [item] Block to execute for each item
1085
+ # @return [Native] New array with mapped values
1086
+ def js_map(arr, &block)
1087
+ `#{arr}.map(#{block})`
1088
+ end
1089
+
1090
+ # Filter array with block
1091
+ # @param arr [Native] JavaScript array
1092
+ # @yield [item] Block to execute for each item
1093
+ # @return [Native] Filtered array
1094
+ def js_filter(arr, &block)
1095
+ `#{arr}.filter(#{block})`
1096
+ end
1097
+
1098
+ # Reduce array with block
1099
+ # @param arr [Native] JavaScript array
1100
+ # @param initial [Object] Initial value
1101
+ # @yield [acc, item] Block to execute for each item
1102
+ # @return [Object] Reduced value
1103
+ def js_reduce(arr, initial, &block)
1104
+ `#{arr}.reduce(#{block}, #{initial})`
1105
+ end
1106
+
1107
+ # ForEach over array with block
1108
+ # @param arr [Native] JavaScript array
1109
+ # @yield [item, index] Block to execute for each item
1110
+ def js_each(arr, &block)
1111
+ `#{arr}.forEach(#{block})`
1112
+ end
1113
+
1114
+ # Slice array
1115
+ # @param arr [Native] JavaScript array
1116
+ # @param start [Integer] Start index
1117
+ # @param end_idx [Integer, nil] End index (optional)
1118
+ # @return [Native] Sliced array
1119
+ def js_slice(arr, start, end_idx = nil)
1120
+ if end_idx
1121
+ `#{arr}.slice(#{start}, #{end_idx})`
1122
+ else
1123
+ `#{arr}.slice(#{start})`
1124
+ end
1125
+ end
1126
+
1127
+ # ===== Object Methods =====
1128
+
1129
+ # Create empty JavaScript object
1130
+ # @return [Native] Empty JavaScript object
1131
+ def js_object
1132
+ `{}`
1133
+ end
1134
+
1135
+ # Get object keys
1136
+ # @param obj [Native] JavaScript object
1137
+ # @return [Native] Array of keys
1138
+ def js_keys(obj)
1139
+ `Object.keys(#{obj})`
1140
+ end
1141
+
1142
+ # Get object values
1143
+ # @param obj [Native] JavaScript object
1144
+ # @return [Native] Array of values
1145
+ def js_values(obj)
1146
+ `Object.values(#{obj})`
1147
+ end
1148
+
1149
+ # Get object entries
1150
+ # @param obj [Native] JavaScript object
1151
+ # @return [Native] Array of [key, value] pairs
1152
+ def js_entries(obj)
1153
+ `Object.entries(#{obj})`
1154
+ end
1155
+
1156
+ # Create Set from array and get size
1157
+ # @param arr [Native] JavaScript array
1158
+ # @return [Integer] Number of unique elements
1159
+ def js_unique_count(arr)
1160
+ `new Set(#{arr}).size`
1161
+ end
1162
+
1163
+ # ===== Fetch API =====
1164
+
1165
+ # Simple fetch that returns Promise-wrapped response
1166
+ # @param url [String] URL to fetch
1167
+ # @return [Native] Promise
1168
+ def js_fetch(url)
1169
+ `fetch(#{url})`
1170
+ end
1171
+
1172
+ # Fetch JSON from URL with callback
1173
+ # @param url [String] URL to fetch
1174
+ # @yield [data] Block to handle response data
1175
+ def fetch_json(url, &success_block)
1176
+ `
1177
+ fetch(#{url})
1178
+ .then(response => response.json())
1179
+ .then(data => #{success_block}.$call(data))
1180
+ .catch(error => console.error('Fetch error:', error))
1181
+ `
1182
+ end
1183
+
1184
+ # Fetch JSON from URL returning a Promise (for chaining)
1185
+ # @param url [String] URL to fetch
1186
+ # @return [Native] Promise that resolves to JSON data
1187
+ def fetch_json_promise(url)
1188
+ `fetch(#{url}).then(response => response.json())`
1189
+ end
1190
+
1191
+ # Fetch JSON with response validation
1192
+ # @param url [String] URL to fetch
1193
+ # @return [Native] Promise that resolves to JSON data or rejects on error
1194
+ def fetch_json_safe(url)
1195
+ `fetch(#{url}).then(function(response) { if (!response.ok) { throw new Error('Network response was not ok: ' + response.status); } return response.json(); })`
1196
+ end
1197
+
1198
+ # Fetch multiple URLs in parallel and get JSON results
1199
+ # @param urls [Array<String>] URLs to fetch
1200
+ # @return [Native] Promise that resolves to array of JSON results
1201
+ def fetch_all_json(urls)
1202
+ promises = urls.map { |url| fetch_json_promise(url) }
1203
+ `Promise.all(#{promises})`
1204
+ end
1205
+
1206
+ # Fetch JSON with success and error callbacks
1207
+ # @param url [String] URL to fetch
1208
+ # @param on_success [Proc] Success callback receiving data
1209
+ # @param on_error [Proc] Error callback receiving error
1210
+ def fetch_json_with_handlers(url, on_success:, on_error: nil)
1211
+ promise = fetch_json_safe(url)
1212
+ promise = js_then(promise) { |data| on_success.call(data) }
1213
+ if on_error
1214
+ js_catch(promise) { |error| on_error.call(error) }
1215
+ else
1216
+ js_catch(promise) { |error| console_error('Fetch error:', error) }
1217
+ end
1218
+ end
1219
+
1220
+ # ===== Promise Methods =====
1221
+
1222
+ # Create Promise.all from array of promises
1223
+ # @param promises [Array<Native>] Array of promises
1224
+ # @return [Native] Promise that resolves when all complete
1225
+ def promise_all(promises)
1226
+ `Promise.all(#{promises})`
1227
+ end
1228
+
1229
+ # Create Promise.race from array of promises
1230
+ # @param promises [Array<Native>] Array of promises
1231
+ # @return [Native] Promise that resolves when first completes
1232
+ def promise_race(promises)
1233
+ `Promise.race(#{promises})`
1234
+ end
1235
+
1236
+ # Create a resolved Promise with value
1237
+ # @param value [Object] Value to resolve with
1238
+ # @return [Native] Resolved Promise
1239
+ def promise_resolve(value)
1240
+ native_value = value.respond_to?(:to_n) ? value.to_n : value
1241
+ `Promise.resolve(#{native_value})`
1242
+ end
1243
+
1244
+ # Create a rejected Promise with error
1245
+ # @param error [Object] Error to reject with
1246
+ # @return [Native] Rejected Promise
1247
+ def promise_reject(error)
1248
+ `Promise.reject(#{error})`
1249
+ end
1250
+
1251
+ # Add then handler to promise
1252
+ # @param promise [Native] JavaScript Promise
1253
+ # @yield [value] Block to handle resolved value
1254
+ # @return [Native] New Promise
1255
+ def js_then(promise, &block)
1256
+ `#{promise}.then(#{block})`
1257
+ end
1258
+
1259
+ # Add catch handler to promise
1260
+ # @param promise [Native] JavaScript Promise
1261
+ # @yield [error] Block to handle rejection
1262
+ # @return [Native] New Promise
1263
+ def js_catch(promise, &block)
1264
+ `#{promise}.catch(#{block})`
1265
+ end
1266
+
1267
+ # Add finally handler to promise
1268
+ # @param promise [Native] JavaScript Promise
1269
+ # @yield Block to execute regardless of outcome
1270
+ # @return [Native] New Promise
1271
+ def js_finally(promise, &block)
1272
+ `#{promise}.finally(#{block})`
1273
+ end
1274
+
793
1275
  private
794
1276
 
795
1277
  # Convert snake_case to camelCase
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: opal-vite
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.2.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - stofu1234