class Card
Cards are wiki-inspired building blocks.
This documentation is for developers who want to understand:
1. how ruby Card objects work, and 2. how to extend them.
It assumes that you’ve already read the introductory text in {file:README.md}.
Throughout this document we will refer to @card as an instance of a Card
object.
## Names
There are four important card identifiers, sometimes called “marks”. Every card has a unique name, key, and id. Some cards also have a codename.
@card.name # The name, a Card::Name object, is the most recognizable card # mark. @card.key # The key, a String, is a simple lower-case name variant. @card.id # The id is an Integer. @card.codename # The codename, a Symbol, is the name by which a card can be # referred to in code.
All names with the same key (including the key itself) are considered variants of each other. No two cards can have names with the same key. {Card::Name} objects inherit from Strings but add many other methods for common card name patterns, eg ‘“A+B”.to_name.right => “B”`.
Setting
a card’s name, eg ‘@card.name = “New Name”`, will automatically update the key.
-
{Card::Name More on names.}
-
{Card::Codename More on codenames.}
## Type
Every card has a type, and every type itself has an associated card. For example, Paula’s type might be User, so there is also a User card.
The type may be accessed in several ways:
@card.type_id # returns id of type card [Integer] @card.type_name # returns name of type card [Card::Name] @card.type_code # returns codename of type card [Symbol] @card.type_card # returns Cardtype card associated with @card's type [Card] - {Set::All::Type Common type methods}
## Content
There are two primary methods for accessing a card’s content:
@card.db_content # the content as it appears in the database @card.content # the "official" content, which may be different from
db_content when db_content is overridden with a structure rule.
- {Content Processing card content} - {Set::All::Content Common content methods}
## Fetch
The two main ways to retrieve cards are fetching (retrieving cards one at a time) and querying (retrieving lists of cards). More on querying below.
Any of the above marks (name, key, id, codename) can be used to fetch a card, eg:
@card1 = Card.fetch "Garden" # returns the card with the name "Garden" (or, more
precisely, with the key “garden”)
@card2 = Card.fetch 100 # returns the card with the id 100 @card3 = Card.fetch :help # returns the card with the codename help
The fetch API will first try to find the card in the cache and will only look in the database if necessary.
The ‘Card[]` shortcut will return the same results but does not support the full range of advanced options and will not return virtual cards (cards that can be constructed from naming patterns but are not actually in the database).
# equivalent to the above but more concise @card1 = Card["Garden"] @card2 = Card[100] @card3 = Card[:help]
Better still, you can use the ‘#card` method on Strings, Integers, Symbols, and Arrays
# equivalent to the above but even more concise @card1 = "Garden".card @card2 = 100.card @card3 = :help.card
The ‘#card_id`, `#cardname`, and `#codename` methods work on all the same objects and provide convenient shortcuts for quickly fetching and returning card attributes.
- {Card::Fetch::CardClass More on fetching.}
## Query
Card
queries find and return lists of cards, eg:
Card.search type_id: 4 # returns an Array of cards with the type_id of 4. - {Card::Query More on queries}
## Views and Events
Views and events are a _Shark’s_ primary tools for manipulating cards. Views customize card presentation, while events customize card transactions. Or, if you like, views and events respectively alter cards in space and time.
Both views and events are defined in {Cardio::Mod mods}, short for modules or modifications.
- {Set::Format::AbstractFormat#view More on views} - {Set::Event::Api#event More on events}
## Accounts and Permissions
Card
code is always executed in the context of a given user account. Permissions for that account are automatically checked when running a query, performing an action, or rendering a view. A typical query, for example, can only return cards that the current user has permission to read.
You can see the current user with ‘Card::Auth.current`. The permissions of a proxy user can be temporarily assumed using `Card::Auth#as`.
{Card::Auth More on accounts}
Public Class Methods
# File lib/card/cache.rb, line 4 def cache Card::Cache[Card] end
Public Instance Methods
# File lib/card/set/event/delayed_event.rb, line 86 def deserialize_for_active_job! attr attr.each do |attname, val| instance_variable_set("@#{attname}", val) end include_set_modules end
# File lib/card/set/event.rb, line 177 def log_event_call event Rails.logger.debug "#{name}: #{event}" # puts "#{name}: #{event}" # puts "#{Card::Director.to_s}".green end
# File lib/card/set/event.rb, line 163 def rescuing_if_integration is_integration, &block is_integration ? rescuing_integration(&block) : yield end
one failed integration event should not harm others.
# File lib/card/set/event.rb, line 168 def rescuing_integration yield rescue StandardError => e # puts "integration error: #{e.message}".red Card::Error.report e, self ensure true end
attributes that ActiveJob can handle
supercard and superleft are excluded, because it caused issues to have them in delayed job but not fully restored (set modules not included, attributes not retained, etc.) Since we’re supposed to have an actual left by the integrate_with_delay stage, it’s not clear that they’re needed. But if we revisit and find they are needed, then we clearly need to make sure that they are fully restored. At a bare minimum they would need to include set modules.
# File lib/card/set/event/delayed_event.rb, line 10 def serializable_attributes self.class.action_specific_attributes + set_specific.keys - %i[supercard superleft subcards] end
Private Instance Methods
# File lib/card/set/event/delayed_event.rb, line 147 def deserialize_hash_value value value.transform_values do |v| deserialize_value v[:value], v[:type] end end
# File lib/card/set/event/delayed_event.rb, line 134 def deserialize_value val, type case type when "symbol" val.to_sym when "time" DateTime.parse val when "hash" deserialize_hash_value val else val end end
# File lib/card/set/event/delayed_event.rb, line 99 def perform_delayed_job_args event [Card::Director.act&.id, self, serialize_for_active_job, Card::Env.serialize, Card::Auth.serialize, event.simple_method_name] end
# File lib/card/set/event/delayed_event.rb, line 108 def serialize_for_active_job serializable_attributes.each_with_object({}) do |name, hash| hash[name] = instance_variable_get("@#{name}") end end
# File lib/card/set/event/delayed_event.rb, line 130 def serialize_hash_value value value.transform_values { |v| serialize_value(v) } end
# File lib/card/set/event/delayed_event.rb, line 114 def serialize_value value # ActiveJob doesn't accept symbols and Time as arguments case value when Symbol { value: value.to_s, type: "symbol" } when Time { value: value.to_s, type: "time" } when Hash { value: serialize_hash_value(value), type: "hash" } when ActionController::Parameters serialize_value value.to_unsafe_h else { value: value } end end
# File lib/card/set/event/delayed_event.rb, line 95 def set_delayed_job_args event { queue: event.name, priority: event.priority } end