Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Serialize view components #66

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,8 @@ GEM
tzinfo (1.2.7)
thread_safe (~> 0.1)
unicode-display_width (1.7.0)
view_component (2.19.1)
activesupport (>= 5.0.0, < 7.0)
websocket-driver (0.7.3)
websocket-extensions (>= 0.1.0)
websocket-extensions (0.1.5)
Expand All @@ -185,6 +187,7 @@ DEPENDENCIES
spy
sqlite3
standardrb
view_component

BUNDLED WITH
2.1.4
1 change: 1 addition & 0 deletions futurism.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ Gem::Specification.new do |spec|
spec.add_development_dependency "standardrb"
spec.add_development_dependency "sqlite3"
spec.add_development_dependency "spy"
spec.add_development_dependency "view_component"

spec.add_dependency "rack", "~> 2.0"
spec.add_dependency "rails", ">= 5.2"
Expand Down
1 change: 1 addition & 0 deletions lib/futurism.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
require "futurism/engine"
require "futurism/channel"
require "futurism/helpers"
require "futurism/shims/view_component_serializer"

module Futurism
extend ActiveSupport::Autoload
Expand Down
43 changes: 43 additions & 0 deletions lib/futurism/shims/view_component_serializer.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
return unless defined?(ViewComponent)

def serialize_value(value)
if value.is_a?(ActiveRecord::Base) && !value.new_record?
value.to_global_id.to_s
else
value
end
end

def deep_serialize_array(array)
array.map do |value|
if value.is_a?(Hash)
require_relative "../shims/deep_transform_values" unless value.respond_to? :deep_transform_values
value.deep_transform_values { |val| serialize_value(val) }
else
serialize_value(value)
end
end
end

module ViewComponent
module FuturismSerializer
def to_futurism_serialized
deep_serialize_array(@raw_initialization_arguments).to_json
end
end

class Base
# Override base new method so that we can hack into the
# initialization process for each view component
# Ideally, a PR to the ViewComponent team would allow us to remove our implementation
# include FuturismSerializer

def self.new(*arguments, &block)
instance = allocate
instance.singleton_class.include(FuturismSerializer)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this the same as instance.extend(FuturismSerializer) ?

Adds to obj the instance methods from each module given as a parameter.

instance.instance_variable_set("@raw_initialization_arguments", arguments)
instance.send(:initialize, *arguments, &block)
instance
end
end
end
1 change: 1 addition & 0 deletions test/test_helper.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# Configure Rails Environment
ENV["RAILS_ENV"] = "test"

require "view_component"
require_relative "../test/dummy/config/environment"
require "rails/test_help"
require "nokogiri"
Expand Down
76 changes: 76 additions & 0 deletions test/view_components/serializer_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
require "test_helper"

class Futurism::Test < ActiveSupport::TestCase
test "component is a ViewComponent" do
assert_includes NoArgumentComponent.ancestors, ViewComponent::Base
assert_includes SimpleArgumentComponent.ancestors, ViewComponent::Base
assert_includes ComplexArgumentComponent.ancestors, ViewComponent::Base
end

test "component instance responds to #to_futurism_serialized" do
instance = NoArgumentComponent.new
assert_respond_to instance, :to_futurism_serialized
end

test "component instance saves no arguments" do
instance = NoArgumentComponent.new

assert_respond_to instance, :to_futurism_serialized
assert_equal instance.instance_variable_get("@raw_initialization_arguments"), []
assert_equal instance.to_futurism_serialized, [].to_json
end

test "component instance saves simple arguments" do
instance = SimpleArgumentComponent.new(false, "/to/somewhere")

assert_respond_to instance, :to_futurism_serialized
assert_equal instance.instance_variable_get("@raw_initialization_arguments"), [false, "/to/somewhere"]
assert_equal instance.to_futurism_serialized, [false, "/to/somewhere"].to_json
end

test "component instance saves complex arguments" do
post = Post.create title: "Lorem"
instance = ComplexArgumentComponent.new(false, "/to/somewhere", deactivate: "Deactivate!", active: "Activate!", ar_object: post)

assert_respond_to instance, :to_futurism_serialized
assert_equal instance.instance_variable_get("@raw_initialization_arguments"), [false, "/to/somewhere", deactivate: "Deactivate!", active: "Activate!", ar_object: post]
assert_equal instance.to_futurism_serialized, [false, "/to/somewhere", deactivate: "Deactivate!", active: "Activate!", ar_object: post.to_global_id.to_s].to_json
end
end

class NoArgumentComponent < ViewComponent::Base
def call
link_to active? ? "Deactivate" : "Activate", "/to/somewhere"
end

def active?
[true, false].sample
end
end

class SimpleArgumentComponent < ViewComponent::Base
def initialize(active, path)
@active, @path = active, path
end

def call
link_to active ? "Deactivate" : "Activate", path
end

attr_reader :active, :path
end

class ComplexArgumentComponent < ViewComponent::Base
def initialize(active, path, decativate: "Deactivate", activate: "Activate", **others)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo

Suggested change
def initialize(active, path, decativate: "Deactivate", activate: "Activate", **others)
def initialize(active, path, deactivate: "Deactivate", activate: "Activate", **others)

@active, @path = active, path
@deactivate = decativate
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo `

Suggested change
@deactivate = decativate
@deactivate = deactivate

@activate = activate
@others = others
end

def call
link_to active ? "Deactivate" : "Activate", path
end

attr_reader :active, :path, :deactivate, :activate, :others
end