joys 0.1.2 → 0.1.4

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.
@@ -0,0 +1,133 @@
1
+ # frozen_string_literal: true
2
+ module Joys
3
+ def self.html(&block)
4
+ renderer = Object.new
5
+ renderer.extend(Render::Helpers)
6
+ renderer.extend(Tags)
7
+ renderer.instance_variable_set(:@bf, String.new)
8
+ renderer.instance_variable_set(:@current_page, "page_standalone")
9
+ renderer.instance_variable_set(:@used_components, Set.new)
10
+ renderer.instance_variable_set(:@slots, {})
11
+ renderer.instance_eval(&block)
12
+ renderer.instance_variable_get(:@bf)
13
+ end
14
+ module Config
15
+ class << self
16
+ attr_accessor :env,:pages,:layouts,:components,:css_parts,:helpers,:markup_parser
17
+ def markup_parser
18
+ @markup_parser ||= ->(content) { content.to_s }
19
+ end
20
+ def env;@env||=ENV['JOYS_ENV']||(defined?(::Rails) ? ::Rails.env.to_s : "development");end
21
+ def dev?;env!="production";end
22
+ def pages;@pages||=path("pages");end
23
+ def layouts;@layouts||=path("layouts");end
24
+ def components;@components||=path("components");end
25
+ def css_parts;@css_parts||=path("css");end
26
+ def helpers;@helpers||=path("helpers");end
27
+ private
28
+ def path(t);defined?(::Rails) ? ::Rails.root.join("app/views/joys/#{t}").to_s : "views/joys/#{t}";end
29
+ end
30
+ end
31
+ module Adapters
32
+ class Base
33
+ def integrate!;raise NotImplementedError;end
34
+ def inject_helpers!;raise NotImplementedError;end
35
+ def controller_context(controller);{};end
36
+ end
37
+ class Rails < Base
38
+ def integrate!
39
+ return unless defined?(ActionController::Base)
40
+ ActionController::Base.include(ControllerMethods)
41
+ inject_helpers!
42
+ ::Rails.application.config.to_prepare do
43
+ Joys.preload! if ::Rails.env.production?
44
+ Joys::Render::Helpers.include(::Rails.application.helpers)
45
+ end
46
+ end
47
+ def inject_helpers!
48
+ Joys::Render::Helpers.include(ActionView::Helpers)
49
+ Joys::Render::Helpers.module_eval do
50
+ def request;Thread.current[:joys_request];end
51
+ def params;Thread.current[:joys_params];end
52
+ def current_user;Thread.current[:joys_current_user];end
53
+ def session;Thread.current[:joys_session];end
54
+ def _(content);raw(content);end
55
+ end
56
+ end
57
+ def controller_context(controller)
58
+ {
59
+ joys_request: controller.request,
60
+ joys_params: controller.params,
61
+ joys_current_user: (controller.current_user if controller.respond_to?(:current_user)),
62
+ joys_session: controller.session
63
+ }
64
+ end
65
+ module ControllerMethods
66
+ def render_joy(path,**locals)
67
+ context=Joys.adapter.controller_context(self)
68
+ context.each{|k,v|Thread.current[k]=v}
69
+ result=Joys.render_joy(path,**locals)
70
+ render html:result.html_safe,layout:false
71
+ ensure
72
+ context&.keys&.each{|k|Thread.current[k]=nil}
73
+ end
74
+ end
75
+ end
76
+ class Sinatra < Base
77
+ def integrate!;end
78
+ def inject_helpers!;end
79
+ end
80
+ class Hanami < Base
81
+ def integrate!;end
82
+ def inject_helpers!;end
83
+ end
84
+ class Roda < Base
85
+ def integrate!;end
86
+ def inject_helpers!;end
87
+ end
88
+ end
89
+ class << self
90
+ attr_accessor :adapter,:css_registry
91
+ def render_joy(path,**locals)
92
+ reload! if Config.dev?
93
+ file=File.join(Config.pages,"#{path}.rb")
94
+ raise "Template not found: #{file}" unless File.exist?(file)
95
+ locals.each{|k,v|eval("@#{k}=v",binding)}
96
+ result=eval(File.read(file),binding,file)
97
+ result.is_a?(String) ? result.freeze : ""
98
+ end
99
+ def preload!;load_helpers;load_dir(Config.layouts);load_dir(Config.components);load_css_parts;end
100
+ def load_helpers
101
+ return unless Dir.exist?(Config.helpers)
102
+ Dir.glob("#{Config.helpers}/**/*.rb").each do |f|
103
+ helper_module = Module.new
104
+ helper_module.module_eval(File.read(f), f)
105
+ Joys::Render::Helpers.include(helper_module)
106
+ end
107
+ end
108
+ def load_css_parts
109
+ return unless Dir.exist?(Config.css_parts)
110
+ Dir.glob("#{Config.css_parts}/**/*.css").each do |f|
111
+ relative_path = f.sub("#{Config.css_parts}/", '').sub('.css', '')
112
+ @css_registry[relative_path] = File.read(f).gsub(/\r\n?|\n/, '')
113
+ end
114
+ end
115
+ def detect_framework!
116
+ @css_registry={}
117
+ @adapter=if defined?(ActionController::Base)&&defined?(::Rails)
118
+ Adapters::Rails.new
119
+ elsif defined?(Sinatra::Base)
120
+ Adapters::Sinatra.new
121
+ elsif defined?(Hanami::Action)
122
+ Adapters::Hanami.new
123
+ elsif defined?(Roda)
124
+ Adapters::Roda.new
125
+ end
126
+ @adapter&.integrate!
127
+ end
128
+ private
129
+ def reload!;clear_cache!;@css_registry={};preload!;end
130
+ def load_dir(dir);Dir.exist?(dir)&&Dir.glob("#{dir}/**/*.rb").each{|f|load f};end
131
+ end
132
+ end
133
+ Joys.detect_framework!
data/lib/joys/core.rb CHANGED
@@ -4,18 +4,27 @@ module Joys
4
4
  @css_path = "public/css";@cache={};@templates={};@compiled_styles={};@consolidated_cache={};@current_component = nil;@layouts={}
5
5
  class << self
6
6
  attr_reader :cache, :templates, :compiled_styles, :consolidated_cache, :layouts
7
- attr_accessor :current_component, :current_page, :css_path
7
+ attr_accessor :current_component, :current_page, :css_path,:adapter,:css_registry
8
+ # def load_css_parts
9
+ # return unless Dir.exist?(Config.css_parts)
10
+ # Dir.glob("#{Config.css_parts}/**/*.css").each do |f|
11
+ # relative_path = f.sub("#{Config.css_parts}/", '').sub('.css', '')
12
+ # @css_registry[relative_path] = File.read(f).gsub(/\r?\n/, "")
13
+ # end
14
+ # end
8
15
  end
16
+ def self.make(name, *args, **kwargs, &block)
17
+ Joys.define :comp, name, *args, **kwargs, &block
18
+ end
9
19
  def self.reset!
10
- @cache.clear
11
- @templates.clear
12
- @compiled_styles.clear
13
- @consolidated_cache.clear
14
- @layouts.clear
15
- @current_component = nil
16
- @current_page = nil
17
- end
18
-
20
+ @cache.clear
21
+ @templates.clear
22
+ @compiled_styles.clear
23
+ @consolidated_cache.clear
24
+ @layouts.clear
25
+ @current_component = nil
26
+ @current_page = nil
27
+ end
19
28
  def self.cache(cache_id, *args, &block);cache_key = [cache_id, args.hash];@cache[cache_key] ||= block.call;end
20
29
  def self.define(type, name, &template)
21
30
  full_name = "#{type}_#{name}";@templates[full_name] = template
@@ -52,7 +61,8 @@ end
52
61
  old_component = @current_component
53
62
  @current_component = full_name if type == :comp
54
63
  result = cache(full_name, *args) do
55
- Joys::Render.compile { instance_exec(*args, &template) }
64
+ # This call now returns a hash, and the hash will be cached.
65
+ Joys::Render.compile(full_name) { instance_exec(*args, &template) }
56
66
  end
57
67
  @current_component = old_component
58
68
  result
@@ -85,47 +95,65 @@ end
85
95
  @current_page = old_page
86
96
  renderer.instance_variable_get(:@bf).freeze
87
97
  end
88
- def self.comp(name, *args, **locals, &block)
98
+ def self.comp(name, *args, **locals, &block)
99
+ renderer = Object.new
100
+ renderer.extend(Render::Helpers)
101
+ renderer.extend(Tags)
102
+ locals.each { |k, v| renderer.instance_variable_set("@#{k}", v) }
103
+ renderer.instance_eval do
104
+ @bf = String.new(capacity: 8192)
105
+ @slots = {}
106
+ @used_components = Set.new
107
+ end
108
+
109
+ comp_template = @templates["comp_#{name}"]
110
+ raise "No comp template defined for #{name}" unless comp_template
111
+
112
+ old_component = @current_component
113
+ @current_component = "comp_#{name}"
114
+
115
+ # Pass the block as a regular argument to the template
116
+ renderer.instance_exec(*args, block, &comp_template)
117
+
118
+ @current_component = old_component
119
+ renderer.instance_variable_get(:@bf).freeze
120
+ end
121
+ def self.html(&block)
122
+ # Clear any previous tracking
123
+ clear_tracked_components
124
+
89
125
  renderer = Object.new
90
126
  renderer.extend(Render::Helpers)
91
127
  renderer.extend(Tags)
92
- locals.each { |k, v| renderer.instance_variable_set("@#{k}", v) }
93
- renderer.instance_eval do
94
- @bf = String.new(capacity: 8192)
95
- @slots = {}
96
- @used_components = Set.new
97
- end
128
+ renderer.instance_variable_set(:@bf, String.new)
129
+ renderer.instance_variable_set(:@current_page, "page_standalone")
130
+ renderer.instance_variable_set(:@used_components, Set.new)
131
+ renderer.instance_variable_set(:@slots, {})
98
132
 
99
- comp_template = @templates["comp_#{name}"]
100
- raise "No comp template defined for #{name}" unless comp_template
133
+ renderer.instance_eval(&block)
101
134
 
102
- old_component = @current_component
103
- @current_component = "comp_#{name}"
135
+ # Merge globally tracked components
136
+ tracked = get_tracked_components
137
+ used = renderer.instance_variable_get(:@used_components)
138
+ used.merge(tracked) if tracked
104
139
 
105
- # Pass the block as a regular argument to the template
106
- renderer.instance_exec(*args, block, &comp_template)
140
+ # Clear tracking after use
141
+ clear_tracked_components
107
142
 
108
- @current_component = old_component
109
- renderer.instance_variable_get(:@bf).freeze
143
+ renderer.instance_variable_get(:@bf)
110
144
  end
111
- def self.html(&block)
112
- renderer = Object.new
113
- renderer.extend(Render::Helpers)
114
- renderer.extend(Tags)
115
- renderer.instance_variable_set(:@bf, String.new)
116
-
117
- # Only inherit page context for style compilation
118
- renderer.instance_variable_set(:@current_page, current_page) if current_page
119
-
120
- renderer.instance_eval(&block)
121
- renderer.instance_variable_get(:@bf)
122
- end
123
145
  module Render
124
- def self.compile(&block)
125
- context = Object.new;context.extend(Helpers);context.extend(Tags)
126
- context.instance_eval { @bf = String.new(capacity: 8192);@slots={};@used_components = Set.new}
146
+ def self.compile(context_name = nil, &block)
147
+ context = Object.new; context.extend(Helpers); context.extend(Tags)
148
+ context.instance_eval { @bf = String.new(capacity: 8192); @slots={}; @used_components = Set.new }
149
+ context.instance_variable_set(:@current_page, context_name) if context_name
127
150
  context.instance_eval(&block)
128
- context.instance_variable_get(:@bf).freeze
151
+
152
+ # CHANGE: Return a hash containing both html and the used components set
153
+ {
154
+ html: context.instance_variable_get(:@bf).freeze,
155
+ components: context.instance_variable_get(:@used_components)
156
+ }
129
157
  end
130
158
  def self.layout(&layout_block)
131
159
  template = Object.new;template.extend(Helpers);template.extend(Tags)