Skip to content

Commit fa5fcf7

Browse files
committed
wip
1 parent b1104aa commit fa5fcf7

25 files changed

+5613
-0
lines changed

array_to_hash_experiment.rb

Lines changed: 237 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,237 @@
1+
#!/usr/bin/env ruby
2+
3+
require 'bundler/setup'
4+
require 'benchmark'
5+
require 'json'
6+
7+
# Convert array to hash with numeric keys
8+
def array_to_hash(array)
9+
hash = {}
10+
array.each_with_index do |item, index|
11+
hash[index.to_s] = item
12+
end
13+
hash
14+
end
15+
16+
# Convert hash back to array (preserve order)
17+
def hash_to_array(hash)
18+
# Sort by numeric key to preserve order
19+
hash.keys.sort_by(&:to_i).map { |key| hash[key] }
20+
end
21+
22+
# Test the conversion
23+
users_array = [
24+
{ id: 1, name: "Alice" },
25+
{ id: 2, name: "Bob" },
26+
{ id: 3, name: "Charlie" }
27+
]
28+
29+
puts "Original array:"
30+
puts users_array.inspect
31+
32+
# Convert to hash
33+
users_hash = array_to_hash(users_array)
34+
puts "\nAs hash:"
35+
puts users_hash.inspect
36+
37+
# Convert back to array
38+
restored_array = hash_to_array(users_hash)
39+
puts "\nRestored array:"
40+
puts restored_array.inspect
41+
42+
puts "\nAre they equal? #{users_array == restored_array}"
43+
44+
# Test JSON serialization
45+
original_json = JSON.generate(users_array)
46+
hash_json = JSON.generate(users_hash)
47+
restored_json = JSON.generate(restored_array)
48+
49+
puts "\nJSON comparison:"
50+
puts "Original: #{original_json}"
51+
puts "Hash: #{hash_json}"
52+
puts "Restored: #{restored_json}"
53+
54+
# But we can reconstruct the array format in JSON
55+
def hash_to_array_json(hash)
56+
sorted_values = hash.keys.sort_by(&:to_i).map { |key| hash[key] }
57+
JSON.generate(sorted_values)
58+
end
59+
60+
reconstructed_json = hash_to_array_json(users_hash)
61+
puts "Reconstructed: #{reconstructed_json}"
62+
puts "JSON equal? #{original_json == reconstructed_json}"
63+
64+
# Now let's test caching with this approach
65+
class HashArrayDSL
66+
def initialize
67+
@root = {}
68+
@stack = []
69+
@current = @root
70+
@array_markers = {} # Track which keys should be arrays
71+
end
72+
73+
def set!(key, value = nil, options = {})
74+
key = key.to_s
75+
76+
if options[:cache] && (cached_data = Rails.cache.read(options[:cache]))
77+
# Cached data is already a hash, just merge it
78+
@current[key] = cached_data
79+
return
80+
end
81+
82+
if block_given?
83+
@stack.push(@current)
84+
old_current = @current
85+
@current = {}
86+
87+
result = yield
88+
89+
if result == :array_marker
90+
@array_markers[generate_path(old_current, key)] = true
91+
end
92+
93+
old_current[key] = @current
94+
95+
# Cache the result if requested
96+
if options[:cache]
97+
Rails.cache.write(options[:cache], @current)
98+
end
99+
100+
@current = @stack.pop
101+
else
102+
@current[key] = value
103+
end
104+
105+
nil
106+
end
107+
108+
def array!(collection = nil, &block)
109+
if collection
110+
collection.each_with_index do |item, index|
111+
@stack.push(@current)
112+
item_obj = {}
113+
@current = item_obj
114+
115+
yield item
116+
117+
@current = @stack.pop
118+
@current[index.to_s] = item_obj # Use string index as key
119+
end
120+
end
121+
122+
:array_marker
123+
end
124+
125+
def result!
126+
JSON.generate(convert_hash_arrays_to_json(@root, @array_markers, ""))
127+
end
128+
129+
private
130+
131+
def generate_path(parent, key)
132+
# This is simplified - would need proper path tracking
133+
key
134+
end
135+
136+
def convert_hash_arrays_to_json(obj, markers, path)
137+
if obj.is_a?(Hash)
138+
if markers[path] || has_numeric_keys(obj)
139+
# Convert hash with numeric keys back to array
140+
sorted_items = obj.keys.sort_by(&:to_i).map do |key|
141+
item_path = "#{path}.#{key}"
142+
convert_hash_arrays_to_json(obj[key], markers, item_path)
143+
end
144+
return sorted_items
145+
else
146+
# Regular object
147+
result = {}
148+
obj.each do |key, value|
149+
item_path = "#{path}.#{key}"
150+
result[key] = convert_hash_arrays_to_json(value, markers, item_path)
151+
end
152+
return result
153+
end
154+
else
155+
obj
156+
end
157+
end
158+
159+
def has_numeric_keys(hash)
160+
return false unless hash.is_a?(Hash)
161+
return false if hash.empty?
162+
163+
# Check if all keys are numeric strings in sequence
164+
keys = hash.keys.sort_by(&:to_i)
165+
keys == (0...keys.length).map(&:to_s)
166+
end
167+
end
168+
169+
# Test this approach
170+
puts "\n=== Testing Hash-Array DSL ==="
171+
172+
# Mock Rails.cache for testing
173+
module Rails
174+
class << self
175+
def cache
176+
@cache ||= MockCache.new
177+
end
178+
end
179+
180+
class MockCache
181+
def initialize
182+
@data = {}
183+
end
184+
185+
def read(key)
186+
@data[key]
187+
end
188+
189+
def write(key, value)
190+
@data[key] = value
191+
end
192+
193+
def clear
194+
@data.clear
195+
end
196+
end
197+
end
198+
199+
Rails.cache.clear
200+
201+
# Test the DSL
202+
dsl = HashArrayDSL.new
203+
dsl.set!(:users) do
204+
dsl.array!(users_array) do |user|
205+
dsl.set!(:id, user[:id])
206+
dsl.set!(:name, user[:name])
207+
end
208+
end
209+
dsl.set!(:status, "success")
210+
211+
result = dsl.result!
212+
puts "DSL Result: #{result}"
213+
214+
# Test with caching
215+
Rails.cache.clear
216+
dsl2 = HashArrayDSL.new
217+
218+
# First render - should cache
219+
dsl2.set!(:users, cache: "users_key") do
220+
dsl2.array!(users_array) do |user|
221+
dsl2.set!(:id, user[:id])
222+
dsl2.set!(:name, user[:name])
223+
end
224+
end
225+
226+
puts "Cached data: #{Rails.cache.read('users_key')}"
227+
228+
# Second render - should use cache
229+
dsl3 = HashArrayDSL.new
230+
dsl3.set!(:users, cache: "users_key") do
231+
# This block shouldn't execute
232+
raise "Cache miss!"
233+
end
234+
dsl3.set!(:status, "from_cache")
235+
236+
cached_result = dsl3.result!
237+
puts "Cached Result: #{cached_result}"

0 commit comments

Comments
 (0)