frontyard 0.1.0

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: 960f8a9f31969989aba04d9cd0fddff4153b60df76259be27e198324eb458e98
4
+ data.tar.gz: 6b5e2e66c25ac43087e9236c0631321b308fb23f48c740c82fce9395bc76d39a
5
+ SHA512:
6
+ metadata.gz: 8911bfaa2be547720a2a1567b4018e6e3d21b0dd8fc6100543e4672cf702f3e772aef2e1916c1044050c1106cd0ed00d111a5f247d2ad34d234f28315b2d5fb4
7
+ data.tar.gz: 90f8f27eaae7a36bfa4eb1f8a8a7c5311393dc756de4415bfaca993875939047121f95c219254eb6a4fa025dadd2ac410d50263c02ba8ca1ce73b9098b3777ac
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright Jim Gay
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,34 @@
1
+ # Frontyard
2
+ Make it easier to use Phlex views, forms, and components.
3
+
4
+ Very much work in progress to find some common patterns.
5
+
6
+ ## Usage
7
+
8
+ TODO…
9
+
10
+ ## Installation
11
+ Add this line to your application's Gemfile:
12
+
13
+ ```ruby
14
+ gem "frontyard"
15
+ ```
16
+
17
+ And then execute:
18
+ ```bash
19
+ $ bundle
20
+ ```
21
+
22
+ Or install it yourself as:
23
+ ```bash
24
+ $ gem install frontyard
25
+ ```
26
+
27
+ ## Contributing
28
+
29
+ ## Releasing
30
+
31
+ This gem uses [Reissue](https://github.com/SOFware/reissue) for versioning and changelog management.
32
+
33
+ ## License
34
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,25 @@
1
+ require "bundler/setup"
2
+
3
+ APP_RAKEFILE = File.expand_path("test/dummy/Rakefile", __dir__)
4
+ load "rails/tasks/engine.rake"
5
+
6
+ load "rails/tasks/statistics.rake"
7
+
8
+ require "bundler/gem_tasks"
9
+
10
+ require "reissue/gem"
11
+
12
+ require "rake/testtask"
13
+
14
+ Reissue::Task.create do |t|
15
+ t.version_file = "frontyard/version.rb"
16
+ end
17
+
18
+ Rake::TestTask.new(:test) do |t|
19
+ t.libs << "test"
20
+ t.libs << "lib"
21
+ t.test_files = FileList["test/**/*_test.rb"]
22
+ t.warning = false
23
+ end
24
+
25
+ task default: :test
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Frontyard
4
+ class Actions < Frontyard::ApplicationComponent
5
+ ButtonConfig = Config.init(
6
+ buttons: {
7
+ submit: {
8
+ type: "submit",
9
+ text: "Submit"
10
+ },
11
+ cancel: {
12
+ type: "cancel",
13
+ text: "Cancel"
14
+ }
15
+ }
16
+ )
17
+
18
+ def initialize(**kwargs, &block)
19
+ filtered_kwargs = filter_kwargs_for(self.class.superclass, kwargs)
20
+ super(&block)
21
+ @button_config = ButtonConfig.merge(kwargs.except(*filtered_kwargs.keys))
22
+ end
23
+
24
+ def view_template(&block)
25
+ div(**self.class.config) do
26
+ if block_given?
27
+ yield
28
+ else
29
+ @button_config[:buttons].each do |_key, data|
30
+ button(type: data[:type]) { data[:text] }
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,188 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Frontyard
4
+ class ApplicationComponent < Phlex::HTML
5
+ include Phlex::Rails::Helpers::Routes
6
+ include Phlex::Rails::Helpers::DOMID
7
+ include Phlex::Rails::Helpers::LinkTo
8
+ include Phlex::Rails::Helpers::ButtonTo
9
+
10
+ class << self
11
+ def default_config
12
+ @default_config ||= Config.init(
13
+ class: generate_css_class
14
+ )
15
+ end
16
+
17
+ def generate_css_class
18
+ return "" if name == "Frontyard::ApplicationComponent"
19
+ class_name = name
20
+ if class_name.to_s.start_with?("Frontyard::") && class_name.to_s != "Frontyard::ApplicationComponent"
21
+ return class_name.split("::").map { |part| part.gsub(/([A-Z])/, '-\1').downcase.sub(/^-/, "") }.join("-")
22
+ end
23
+ return "frontyard-component" if class_name.nil? || class_name.start_with?("#<")
24
+ this_css_class = class_name.split("::").last.gsub(/([A-Z])/, '-\1').downcase.sub(/^-/, "")
25
+ if superclass.respond_to?(:generate_css_class)
26
+ css_class = Contours::StructuredString.new(superclass.generate_css_class)
27
+ css_class << this_css_class
28
+ else
29
+ this_css_class
30
+ end.to_s
31
+ end
32
+
33
+ def config
34
+ @config ||= default_config
35
+ end
36
+
37
+ private
38
+
39
+ def configure(**kwargs)
40
+ @config = Config.init(kwargs)
41
+ end
42
+ end
43
+
44
+ def before_template
45
+ if Rails.env.development?
46
+ comment { "Before #{self.class.name}" }
47
+ end
48
+ super
49
+ end
50
+
51
+ def html_options
52
+ @html_options || self.class.config
53
+ end
54
+
55
+ def namespace = @namespace ||= begin
56
+ ns = self.class.name.deconstantize
57
+ ns.empty? ? Object : Object.const_get(ns)
58
+ end
59
+
60
+ # Define an initialize method along with attr_accessors
61
+ #
62
+ # Example:
63
+ # initialize_with :some, :keyword, optional: nil
64
+ # initialize_with :some, :keyword, optional: nil do
65
+ # @processed_data = some.upcase
66
+ # end
67
+ def self.initialize_with(*keys, **kwargs, &block)
68
+ mod = Module.new
69
+ tokens = keys.map do |key|
70
+ [
71
+ "#{key}:",
72
+ "@#{key} = #{key}"
73
+ ]
74
+ end.to_h
75
+ kwargs.each do |key, value|
76
+ value ||= "nil"
77
+ tokens["#{key}: #{value}"] = "@#{key} = #{key}"
78
+ end
79
+ accessors = keys + kwargs.keys
80
+ keyword_args = tokens.keys
81
+ ivars = tokens.values
82
+
83
+ # Include the block code in the initialize method if provided
84
+ block_code = if block_given?
85
+ # Convert the block to a string representation that can be executed
86
+ # This is a simplified approach - in practice you might want to use a more robust method
87
+ "instance_eval(&self.class.instance_variable_get(:@initialize_block))"
88
+ else
89
+ ""
90
+ end
91
+
92
+ mod.class_eval <<~RUBY, __FILE__, __LINE__ + 1
93
+ def initialize(#{keyword_args.join(", ")}, **options)
94
+ #{ivars.join("\n")}
95
+ @flash = options.delete(:flash) || {}
96
+ if options.key?(:html_options)
97
+ @html_options = options.delete(:html_options)
98
+ end
99
+ @options = options
100
+ yield self if block_given?
101
+ #{block_code}
102
+ end
103
+ RUBY
104
+ accessors += [:flash, :options, :html_options]
105
+ attr_accessor(*accessors)
106
+ const_set(:Initializer, mod)
107
+ include mod
108
+
109
+ # Store the block for execution on instances
110
+ @initialize_block = block if block_given?
111
+ end
112
+
113
+ # Helper to filter kwargs for a class's initialize method
114
+ private def filter_kwargs_for(klass, kwargs)
115
+ accepted = klass.instance_method(:initialize).parameters
116
+ .select { |type, _| type == :key || type == :keyreq }
117
+ .map(&:last)
118
+ kwargs.slice(*accepted)
119
+ end
120
+
121
+ # Helper to safely try multiple constant names
122
+ private def safe_const_get(*names)
123
+ names.each do |name|
124
+ return Object.const_get(name)
125
+ rescue NameError
126
+ next
127
+ end
128
+ raise NameError, "None of the constants found: #{names.join(", ")}"
129
+ end
130
+
131
+ # Rendere the partials that represent a model
132
+ #
133
+ # Example:
134
+ # render_model something: value
135
+ # render_model something: value, from: "widgets/widget"
136
+ def render_model(from: nil, **kwargs)
137
+ const_names = if from
138
+ base = from.classify
139
+ [base, "#{base}Component"]
140
+ else
141
+ namespace = self.class.name.deconstantize
142
+ model_name = namespace.demodulize.singularize
143
+ [
144
+ "#{namespace}::#{model_name}",
145
+ "#{namespace}::#{model_name}Component"
146
+ ]
147
+ end
148
+ klass = safe_const_get(*const_names)
149
+ filtered_kwargs = filter_kwargs_for(klass, kwargs)
150
+ render klass.new(**filtered_kwargs)
151
+ end
152
+
153
+ # Render a table component
154
+ #
155
+ # Example:
156
+ # render_table from: "widgets/widget"
157
+ # render_table from: "widgets/widget", columns: [:name, :description]
158
+ def render_table(from: nil, **kwargs, &block)
159
+ const_names = if from
160
+ base = from.classify
161
+ [base, "#{base}Table"]
162
+ elsif self.class.name.include?("::")
163
+ # For top-level classes (no namespace), try Frontyard namespace first
164
+ namespace = self.class.name.deconstantize
165
+ [
166
+ "#{namespace}::Table",
167
+ "#{namespace}::#{self.class.name.demodulize}Table",
168
+ "#{self.class.name}Table"
169
+ ]
170
+ else
171
+ # Top-level class, try Frontyard namespace with common table names
172
+ [
173
+ "Frontyard::TestTable",
174
+ "Frontyard::Table",
175
+ "Frontyard::#{self.class.name}Table",
176
+ "#{self.class.name}Table"
177
+ ]
178
+ end
179
+ klass = safe_const_get(*const_names)
180
+ filtered_kwargs = filter_kwargs_for(klass, kwargs)
181
+ render klass.new(**filtered_kwargs, &block)
182
+ end
183
+
184
+ def params = helpers.params
185
+
186
+ def view_template(&) = div(**html_options, &)
187
+ end
188
+ end
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Frontyard
4
+ class ApplicationForm < Frontyard::ApplicationComponent
5
+ include Phlex::Rails::Helpers::DatetimeField
6
+ include Phlex::Rails::Helpers::FormWith
7
+ include Phlex::Rails::Helpers::Label
8
+ include Phlex::Rails::Helpers::Pluralize
9
+ include Phlex::Rails::Helpers::TextField
10
+
11
+ def form_actions(**kwargs, &block)
12
+ render Frontyard::Actions.new(**kwargs, &block)
13
+ end
14
+
15
+ def field(attribute, **kwargs, &block)
16
+ # Use the form object if available, otherwise use a default object
17
+ form_object = respond_to?(:object) ? object : self
18
+ render Frontyard::Field.new(object: form_object, attribute: attribute, **kwargs, &block)
19
+ end
20
+
21
+ # Default object method - subclasses can override this
22
+ def object
23
+ nil
24
+ end
25
+
26
+ DateTimeParamTransformer = Data.define(:keys, :hash) do
27
+ def call(time_converter: Time.zone.method(:local))
28
+ leaf = keys.pop
29
+ data = keys.reduce(hash) do |memo, key|
30
+ memo[key] ||= {}
31
+ end
32
+
33
+ values = []
34
+ # Check for both string and symbol keys
35
+ datetime_keys = [
36
+ "#{leaf}(1i)", :"#{leaf}(1i)",
37
+ "#{leaf}(2i)", :"#{leaf}(2i)",
38
+ "#{leaf}(3i)", :"#{leaf}(3i)",
39
+ "#{leaf}(4i)", :"#{leaf}(4i)",
40
+ "#{leaf}(5i)", :"#{leaf}(5i)"
41
+ ]
42
+
43
+ datetime_keys.each_slice(2) do |string_key, symbol_key|
44
+ value = data.delete(string_key) || data.delete(symbol_key)
45
+ values << value if value
46
+ end
47
+
48
+ # Filter out nil values and provide defaults
49
+ filtered_values = values.compact
50
+ if filtered_values.empty?
51
+ # If no values provided, use current time
52
+ Time.current
53
+ else
54
+ # Pad with defaults for missing parts
55
+ year = filtered_values[0] || Time.current.year
56
+ month = filtered_values[1] || 1
57
+ day = filtered_values[2] || 1
58
+ hour = filtered_values[3] || 0
59
+ minute = filtered_values[4] || 0
60
+
61
+ time_converter.call(year, month, day, hour, minute)
62
+ end
63
+ end
64
+ end
65
+
66
+ class << self
67
+ def process_params(params)
68
+ params
69
+ end
70
+
71
+ private
72
+
73
+ def format_date_parts(*keys, params:)
74
+ DateTimeParamTransformer.new(keys: keys, hash: params).call
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,11 @@
1
+ module Frontyard
2
+ class ApplicationTable < ApplicationComponent
3
+ def render_row(**kwargs, &block)
4
+ if self.class.const_defined?(:Row)
5
+ render self.class::Row.new(**kwargs, &block)
6
+ else
7
+ tr(**kwargs, &block)
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Frontyard
4
+ class ApplicationView < ::Frontyard::ApplicationComponent
5
+ include Phlex::Rails::Helpers::ContentFor
6
+
7
+ def page_links(&)
8
+ render PageLinks.new(&)
9
+ end
10
+
11
+ def render_form(**)
12
+ render namespace::Form.new(**)
13
+ end
14
+
15
+ def render_fragment(namespace: nil, **)
16
+ namespace ||= self.namespace
17
+ render "#{namespace}::Fragment".constantize.new(**)
18
+ end
19
+
20
+ def notice = flash[:notice]
21
+
22
+ def alert = flash[:alert]
23
+
24
+ def error = flash[:error]
25
+ end
26
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Frontyard
4
+ module Components
5
+ extend Phlex::Kit
6
+ end
7
+ end
@@ -0,0 +1,66 @@
1
+ module Frontyard
2
+ class Field < Frontyard::ApplicationComponent
3
+ include Phlex::Rails::Helpers::FormWith
4
+ include Phlex::Rails::Helpers::Label
5
+ include Phlex::Rails::Helpers::Pluralize
6
+ include Phlex::Rails::Helpers::TextField
7
+ include Phlex::Rails::Helpers::NumberField
8
+ include Phlex::Rails::Helpers::CheckBox
9
+ include Phlex::Rails::Helpers::DateSelect
10
+ include Phlex::Rails::Helpers::OptionsForSelect
11
+ include Phlex::Rails::Helpers::Select
12
+
13
+ initialize_with :object, :attribute
14
+
15
+ def view_template(&block)
16
+ div(**self.class.config) do
17
+ # Use basic HTML label to avoid Rails helper conflicts
18
+ tag(:label) { attribute.to_s.humanize }
19
+
20
+ case field_type
21
+ when :text
22
+ input(type: "text", name: object_attribute, **field_options)
23
+ when :number
24
+ input(type: "number", name: object_attribute, **field_options)
25
+ when :date
26
+ input(type: "date", name: object_attribute, **field_options)
27
+ when :checkbox
28
+ input(type: "checkbox", name: object_attribute, **field_options)
29
+ else
30
+ input(type: "text", name: object_attribute, **field_options)
31
+ end
32
+ yield if block_given?
33
+ end
34
+ end
35
+
36
+ private
37
+
38
+ def object_attribute
39
+ if object&.class&.respond_to?(:name)
40
+ "#{object.class.name.underscore}[#{attribute}]"
41
+ else
42
+ # Fallback for when object is nil or doesn't have a class name
43
+ attribute.to_s
44
+ end
45
+ end
46
+
47
+ def field_type
48
+ # Determine field type based on attribute or object type
49
+ case attribute.to_s
50
+ when /_at$/, /_on$/
51
+ :date
52
+ when /_count$/, /_id$/
53
+ :number
54
+ when /_enabled$/, /_active$/
55
+ :checkbox
56
+ else
57
+ :text
58
+ end
59
+ end
60
+
61
+ def field_options
62
+ # Return any additional options for the field
63
+ {}
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,35 @@
1
+ module Frontyard
2
+ class Fields < Frontyard::ApplicationComponent
3
+ DefaultConfig = Config.init(
4
+ class: "frontyard-fields"
5
+ )
6
+
7
+ def field(*args, **kwargs, &block)
8
+ name = args.first
9
+ options = kwargs
10
+ div(class: "frontyard-field") do
11
+ label do
12
+ plain(name.to_s.humanize)
13
+ input(type: options[:type] || "text", name: name, **render_attributes(options))
14
+ end
15
+ end
16
+ end
17
+
18
+ private
19
+
20
+ def render_attributes(options)
21
+ attrs = options.except(:type)
22
+ # Handle boolean attributes
23
+ attrs.transform_values! do |value|
24
+ if value.is_a?(TrueClass)
25
+ value.to_s
26
+ elsif value.is_a?(FalseClass)
27
+ nil
28
+ else
29
+ value
30
+ end
31
+ end
32
+ attrs.compact
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Frontyard
4
+ class PageLinks < Frontyard::ApplicationComponent
5
+ def page_link(text, url, **options)
6
+ options = {
7
+ class: "page-link"
8
+ }.merge(options)
9
+ link_to text, url, **options
10
+ end
11
+
12
+ def button(text, object, **options)
13
+ options = {
14
+ class: "page-button",
15
+ form: {class: "inline-button-form"}
16
+ }.merge(options)
17
+ button_to text, object, **options
18
+ end
19
+
20
+ def dangerous_button(text, object, options)
21
+ options = {
22
+ class: "page-button dangerous"
23
+ }.merge(options)
24
+ button(text, object, **options)
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,39 @@
1
+ module Frontyard
2
+ module Controller
3
+ # Get the form class for the current controller
4
+ def form
5
+ namespace = controller_name.camelize
6
+ ::Views.const_get("#{namespace}::Form")
7
+ end
8
+
9
+ def form_params
10
+ form.process_params(params)
11
+ end
12
+
13
+ def render_view(action_name: self.action_name, **kwargs)
14
+ klass = "views/#{controller_name}/#{action_name}".classify.constantize
15
+ # Get the initialize parameters from the view class
16
+ init_params = klass.instance_method(:initialize).parameters
17
+ # Symbolize all keys in kwargs
18
+ symbolized_kwargs = kwargs.transform_keys(&:to_sym)
19
+ # Start with kwargs, but fill in required params from controller if missing
20
+ view_data = {}
21
+ init_params.each do |type, name|
22
+ sym_name = name.to_sym
23
+ if symbolized_kwargs.key?(sym_name)
24
+ # Parameter was provided in kwargs
25
+ view_data[sym_name] = symbolized_kwargs[sym_name]
26
+ elsif type == :keyreq && respond_to?(name, true)
27
+ # Required parameter not provided, call controller method
28
+ view_data[sym_name] = send(name)
29
+ elsif type == :key && respond_to?(name, true)
30
+ # Optional parameter not provided, call controller method
31
+ view_data[sym_name] = send(name)
32
+ end
33
+ end
34
+ view_data[:flash] = flash
35
+ render_data = symbolized_kwargs.except(*view_data.keys)
36
+ render klass.new(**view_data), **render_data
37
+ end
38
+ end
39
+ end
data/config/routes.rb ADDED
@@ -0,0 +1,2 @@
1
+ Rails.application.routes.draw do
2
+ end
@@ -0,0 +1,19 @@
1
+ require "phlex-rails"
2
+
3
+ module Frontyard
4
+ class Engine < ::Rails::Engine
5
+ isolate_namespace Frontyard
6
+
7
+ initializer "frontyard.controller" do
8
+ ActiveSupport.on_load(:action_controller) do
9
+ include Frontyard::Controller
10
+ end
11
+ end
12
+
13
+ initializer "frontyard.view" do
14
+ ActiveSupport.on_load(:action_view) do
15
+ Dir[Frontyard::Engine.root.join("app/views/frontyard/**/*.rb")].each { |file| require file }
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,3 @@
1
+ module Frontyard
2
+ VERSION = "0.1.0"
3
+ end
data/lib/frontyard.rb ADDED
@@ -0,0 +1,12 @@
1
+ require_relative "frontyard/version"
2
+ require_relative "frontyard/engine"
3
+ require "contours"
4
+
5
+ module Frontyard
6
+ extend Phlex::Kit
7
+
8
+ class Config < Contours::BlendedHash
9
+ @blended_keys = [:class]
10
+ blend :class, with: Contours::StructuredString
11
+ end
12
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :frontyard do
3
+ # # Task goes here
4
+ # end
metadata ADDED
@@ -0,0 +1,103 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: frontyard
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Jim Gay
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 2025-07-15 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: rails
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - ">="
17
+ - !ruby/object:Gem::Version
18
+ version: 8.0.0
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - ">="
24
+ - !ruby/object:Gem::Version
25
+ version: 8.0.0
26
+ - !ruby/object:Gem::Dependency
27
+ name: phlex-rails
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: 2.0.2
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: 2.0.2
40
+ - !ruby/object:Gem::Dependency
41
+ name: contours
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: 0.1.1
47
+ type: :runtime
48
+ prerelease: false
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: 0.1.1
54
+ description: Use Frontyard in your rails app to simplify the use of Phlex views.
55
+ email:
56
+ - jim@saturnflyer.com
57
+ executables: []
58
+ extensions: []
59
+ extra_rdoc_files: []
60
+ files:
61
+ - MIT-LICENSE
62
+ - README.md
63
+ - Rakefile
64
+ - app/components/frontyard/actions.rb
65
+ - app/components/frontyard/application_component.rb
66
+ - app/components/frontyard/application_form.rb
67
+ - app/components/frontyard/application_table.rb
68
+ - app/components/frontyard/application_view.rb
69
+ - app/components/frontyard/components.rb
70
+ - app/components/frontyard/field.rb
71
+ - app/components/frontyard/fields.rb
72
+ - app/components/frontyard/page_links.rb
73
+ - app/controllers/frontyard/controller.rb
74
+ - config/routes.rb
75
+ - lib/frontyard.rb
76
+ - lib/frontyard/engine.rb
77
+ - lib/frontyard/version.rb
78
+ - lib/tasks/frontyard_tasks.rake
79
+ homepage: https://github.com/saturnflyer/frontyard
80
+ licenses:
81
+ - MIT
82
+ metadata:
83
+ homepage_uri: https://github.com/saturnflyer/frontyard
84
+ source_code_uri: https://github.com/saturnflyer/frontyard
85
+ changelog_uri: https://github.com/saturnflyer/frontyard/blob/main/CHANGELOG.md
86
+ rdoc_options: []
87
+ require_paths:
88
+ - lib
89
+ required_ruby_version: !ruby/object:Gem::Requirement
90
+ requirements:
91
+ - - ">="
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ required_rubygems_version: !ruby/object:Gem::Requirement
95
+ requirements:
96
+ - - ">="
97
+ - !ruby/object:Gem::Version
98
+ version: '0'
99
+ requirements: []
100
+ rubygems_version: 3.6.5
101
+ specification_version: 4
102
+ summary: Frontyard is a Rails engine for creating and managing views with Phlex.
103
+ test_files: []