card 1.18.4 → 1.18.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.yardoc/checksums +263 -240
- data/.yardoc/object_types +0 -0
- data/.yardoc/objects/root.dat +0 -0
- data/VERSION +1 -1
- data/card.gemspec +5 -2
- data/config/initializers/01_core_extensions/array.rb +9 -0
- data/config/initializers/01_core_extensions/hash.rb +57 -0
- data/config/initializers/01_core_extensions/module.rb +14 -0
- data/config/initializers/01_core_extensions/object.rb +43 -0
- data/config/initializers/02_extensions/kaminari.rb +38 -0
- data/config/initializers/core_extensions.rb +24 -0
- data/config/initializers/extensions.rb +3 -0
- data/lib/card.rb +15 -10
- data/lib/card/director_register.rb +7 -0
- data/lib/card/loader.rb +29 -39
- data/lib/card/migration.rb +14 -0
- data/lib/card/query.rb +17 -128
- data/lib/card/query/attributes.rb +2 -244
- data/lib/card/query/conjunctions.rb +36 -0
- data/lib/card/query/helpers.rb +72 -0
- data/lib/card/query/interpretation.rb +124 -0
- data/lib/card/query/relational_attributes.rb +95 -0
- data/lib/card/query/sorting.rb +52 -0
- data/lib/card/set.rb +73 -362
- data/lib/card/set/format.rb +122 -0
- data/lib/card/set/helpers.rb +100 -0
- data/lib/card/set/loader.rb +98 -0
- data/lib/card/set/trait.rb +5 -2
- data/lib/card/subcards.rb +38 -12
- data/lib/cardio.rb +1 -1
- data/lib/generators/card/migration/templates/card_migration.erb +1 -1
- data/mod/01_core/chunk/include.rb +13 -1
- data/mod/01_core/set/all/event.rb +14 -0
- data/mod/01_core/set/all/fetch.rb +21 -7
- data/mod/01_core/set/all/states.rb +3 -1
- data/mod/01_core/set/all/subcards.rb +4 -2
- data/mod/01_core/spec/set/all/fetch_spec.rb +14 -1
- data/mod/02_basic_types/set/abstract/code_file.rb +6 -0
- data/mod/04_settings/set/type/setting.rb +10 -0
- data/mod/05_standard/set/all/rich_html/wrapper.rb +1 -1
- data/mod/05_standard/set/self/codenames.rb +0 -0
- data/mod/05_standard/spec/chunk/include_spec.rb +10 -10
- data/spec/config/initializers/core_extensions_spec.rb +15 -0
- data/spec/lib/card/stage_director_spec.rb +25 -1
- metadata +25 -8
- data/config/initializers/01_init_ruby_extensions.rb +0 -3
- data/lib/card/core_ext.rb +0 -107
@@ -0,0 +1,122 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
2
|
+
|
3
|
+
class Card
|
4
|
+
module Set
|
5
|
+
# Whenever a Format object is instantiated for a card, it
|
6
|
+
# includes all views associated with BOTH (a) sets of which the card is a
|
7
|
+
# member and (b) the current format or its ancestors. More on defining
|
8
|
+
# views below.
|
9
|
+
#
|
10
|
+
# View definitions
|
11
|
+
#
|
12
|
+
# When you declare:
|
13
|
+
# view :view_name do |args|
|
14
|
+
# #...your code here
|
15
|
+
# end
|
16
|
+
#
|
17
|
+
# Methods are defined on the format
|
18
|
+
#
|
19
|
+
# The external api with checks:
|
20
|
+
# render(:viewname, args)
|
21
|
+
#
|
22
|
+
module Format
|
23
|
+
def format *format_names, &block
|
24
|
+
if format_names.empty?
|
25
|
+
format_names = [:base]
|
26
|
+
elsif format_names.first == :all
|
27
|
+
format_names =
|
28
|
+
Card::Format.registered.reject { |f| Card::Format.aliases[f] }
|
29
|
+
end
|
30
|
+
format_names.each do |f|
|
31
|
+
define_on_format f, &block
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def view *args, &block
|
36
|
+
format do
|
37
|
+
view(*args, &block)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def define_on_format format_name=:base, &block
|
42
|
+
# format class name, eg. HtmlFormat
|
43
|
+
klass = Card::Format.format_class_name format_name
|
44
|
+
|
45
|
+
# called on current set module, eg Card::Set::Type::Pointer
|
46
|
+
mod = const_get_or_set klass do
|
47
|
+
# yielding set format module, eg Card::Set::Type::Pointer::HtmlFormat
|
48
|
+
m = Module.new
|
49
|
+
register_set_format Card.const_get(klass), m
|
50
|
+
m.extend Card::Set::AbstractFormat
|
51
|
+
m
|
52
|
+
end
|
53
|
+
mod.class_eval(&block)
|
54
|
+
end
|
55
|
+
|
56
|
+
def register_set_format format_class, mod
|
57
|
+
if all_set?
|
58
|
+
all_set_format_mod! format_class, mod
|
59
|
+
else
|
60
|
+
format_type = abstract_set? ? :abstract_format : :nonbase_format
|
61
|
+
# ready to include dynamically in set members' format singletons
|
62
|
+
format_hash = modules[format_type][format_class] ||= {}
|
63
|
+
format_hash[shortname] ||= []
|
64
|
+
format_hash[shortname] << mod
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
# make mod ready to include in base (non-set-specific) format classes
|
69
|
+
def all_set_format_mod! format_class, mod
|
70
|
+
modules[:base_format][format_class] ||= []
|
71
|
+
modules[:base_format][format_class] << mod
|
72
|
+
end
|
73
|
+
|
74
|
+
# iterate through each format associated with a set
|
75
|
+
def each_format set
|
76
|
+
set_type = set.abstract_set? ? :abstract : :nonbase
|
77
|
+
format_type = "#{set_type}_format".to_sym
|
78
|
+
modules[format_type].each_pair do |format, set_format_mod_hash|
|
79
|
+
next unless (format_mods = set_format_mod_hash[set.shortname])
|
80
|
+
yield format, format_mods
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def applicable_format? format, except, only
|
85
|
+
return false if except && Array(except).include?(format)
|
86
|
+
return false if only && !Array(only).include?(format)
|
87
|
+
true
|
88
|
+
end
|
89
|
+
|
90
|
+
# All Format modules are extended with this module in order to support
|
91
|
+
# the basic format API (ok, view definitions. It's just view
|
92
|
+
# definitions.)
|
93
|
+
module AbstractFormat
|
94
|
+
mattr_accessor :views
|
95
|
+
self.views = {}
|
96
|
+
|
97
|
+
def view view, *args, &block
|
98
|
+
view = view.to_viewname.key.to_sym
|
99
|
+
views[self] ||= {}
|
100
|
+
view_block = views[self][view] =
|
101
|
+
if block_given?
|
102
|
+
Card::Format.extract_class_vars view, args[0]
|
103
|
+
block
|
104
|
+
else
|
105
|
+
lookup_alias_block view, args
|
106
|
+
end
|
107
|
+
define_method "_view_#{view}", view_block
|
108
|
+
end
|
109
|
+
|
110
|
+
def lookup_alias_block view, args
|
111
|
+
opts = args[0].is_a?(Hash) ? args.shift : { view: args.shift }
|
112
|
+
opts[:mod] ||= self
|
113
|
+
opts[:view] ||= view
|
114
|
+
views[opts[:mod]][opts[:view]] || begin
|
115
|
+
raise "cannot find #{opts[:view]} view in #{opts[:mod]}; " \
|
116
|
+
"failed to alias #{view} in #{self}"
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
class Card
|
2
|
+
module Set
|
3
|
+
# advanced set module API
|
4
|
+
module Helpers
|
5
|
+
# include a set module and all its format modules
|
6
|
+
# @param [Module] set
|
7
|
+
# @param [Hash] opts choose the formats you want to include
|
8
|
+
# @option opts [Symbol, Array<Symbol>] :only include only these formats
|
9
|
+
# @option opts [Symbol, Array<Symbol>] :except don't include these formats
|
10
|
+
# @example
|
11
|
+
# include_set Type::Basic, except: :css
|
12
|
+
def include_set set, opts={}
|
13
|
+
set_type = set.abstract_set? ? :abstract : :nonbase
|
14
|
+
Card::Set.modules[set_type][set.shortname].each do |set_mod|
|
15
|
+
include set_mod
|
16
|
+
end
|
17
|
+
include_set_formats set, opts
|
18
|
+
end
|
19
|
+
|
20
|
+
# include a format modules of a set
|
21
|
+
# @param [Module] set
|
22
|
+
# @param [Hash] opts choose the formats you want to include
|
23
|
+
# @option opts [Symbol, Array<Symbol>] :only include only these formats
|
24
|
+
# @option opts [Symbol, Array<Symbol>] :except don't include these formats
|
25
|
+
# @example
|
26
|
+
# include_set Type::Basic, except: :css
|
27
|
+
def include_set_formats set, opts={}
|
28
|
+
each_format set do |format, format_mods|
|
29
|
+
match = format.to_s.match(/::(?<format>[^:]+)Format/)
|
30
|
+
format_sym = match ? match[:format] : :base
|
31
|
+
next unless applicable_format?(format_sym, opts[:except], opts[:only])
|
32
|
+
format_mods.each do |format_mod|
|
33
|
+
define_on_format format_sym do
|
34
|
+
include format_mod
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def ensure_set &block
|
41
|
+
set_module = yield
|
42
|
+
rescue NameError => e
|
43
|
+
if e.message =~ /uninitialized constant (?:Card::Set::)?(.+)$/
|
44
|
+
constant_pieces = Regexp.last_match(1).split('::')
|
45
|
+
constant_pieces.inject(Card::Set) do |set_mod, module_name|
|
46
|
+
set_mod.const_get_or_set module_name do
|
47
|
+
Module.new
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
# try again - there might be another submodule that doesn't exist
|
52
|
+
ensure_set(&block)
|
53
|
+
else
|
54
|
+
set_module.extend Card::Set
|
55
|
+
end
|
56
|
+
|
57
|
+
def attachment name, args
|
58
|
+
include Abstract::Attachment
|
59
|
+
add_attributes name, "remote_#{name}_url".to_sym, :load_from_mod,
|
60
|
+
:action_id_of_cached_upload, :empty_ok
|
61
|
+
uploader_class = args[:uploader] || FileUploader
|
62
|
+
mount_uploader name, uploader_class
|
63
|
+
end
|
64
|
+
|
65
|
+
def stage_method method, opts={}, &block
|
66
|
+
class_eval do
|
67
|
+
define_method "_#{method}", &block
|
68
|
+
define_method method do |*args|
|
69
|
+
if (error = wrong_stage(opts) || wrong_action(opts[:on]))
|
70
|
+
raise Card::Error, error
|
71
|
+
else
|
72
|
+
send "_#{method}", *args
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def shortname
|
79
|
+
parts = name.split '::'
|
80
|
+
first = 2 # shortname eliminates Card::Set
|
81
|
+
pattern_name = parts[first].underscore
|
82
|
+
last = if pattern_name == 'abstract'
|
83
|
+
first + 1
|
84
|
+
else
|
85
|
+
set_class = Card::SetPattern.find pattern_name
|
86
|
+
first + set_class.anchor_parts_count
|
87
|
+
end
|
88
|
+
parts[first..last].join '::'
|
89
|
+
end
|
90
|
+
|
91
|
+
def abstract_set?
|
92
|
+
name =~ /^Card::Set::Abstract::/
|
93
|
+
end
|
94
|
+
|
95
|
+
def all_set?
|
96
|
+
name =~ /^Card::Set::All::/
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
2
|
+
|
3
|
+
class Card
|
4
|
+
module Set
|
5
|
+
# the set loading process has two main phases:
|
6
|
+
|
7
|
+
# 1. Definition: interpret each set file, creating/defining set and
|
8
|
+
# set_format modules
|
9
|
+
# 2. Organization: have base classes include modules associated with the
|
10
|
+
# 'all' set, and clean up the other modules
|
11
|
+
module Loader
|
12
|
+
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
13
|
+
# Definition Phase
|
14
|
+
|
15
|
+
# each set file calls `extend Card::Set` when loaded
|
16
|
+
def extended mod
|
17
|
+
register_set mod
|
18
|
+
end
|
19
|
+
|
20
|
+
# make the set available for use
|
21
|
+
def register_set set_module
|
22
|
+
if set_module.all_set?
|
23
|
+
# automatically included in Card class
|
24
|
+
modules[:base] << set_module
|
25
|
+
else
|
26
|
+
set_type = set_module.abstract_set? ? :abstract : :nonbase
|
27
|
+
# made ready for dynamic loading via #include_set_modules
|
28
|
+
modules[set_type][set_module.shortname] ||= []
|
29
|
+
modules[set_type][set_module.shortname] << set_module
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
#
|
34
|
+
# When a Card application loads, it uses set modules to autogenerate
|
35
|
+
# tmp files that add module names (Card::Set::PATTERN::ANCHOR) and
|
36
|
+
# extend the module with Card::Set.
|
37
|
+
#
|
38
|
+
|
39
|
+
#
|
40
|
+
#
|
41
|
+
def write_tmp_file from_file, to_file, rel_path
|
42
|
+
name_parts = rel_path.gsub(/\.rb/, '').split(File::SEPARATOR)
|
43
|
+
submodules = name_parts.map { |a| "module #{a.camelize};" } * ' '
|
44
|
+
file_content = <<EOF
|
45
|
+
# -*- encoding : utf-8 -*-
|
46
|
+
class Card; module Set; #{submodules} extend Card::Set
|
47
|
+
# ~~~~~~~~~~~ above autogenerated; below pulled from #{from_file} ~~~~~~~~~~~
|
48
|
+
#{File.read from_file}
|
49
|
+
|
50
|
+
# ~~~~~~~~~~~ below autogenerated; above pulled from #{from_file} ~~~~~~~~~~~
|
51
|
+
end;end;#{'end;' * name_parts.size}
|
52
|
+
EOF
|
53
|
+
|
54
|
+
FileUtils.mkdir_p File.dirname(to_file)
|
55
|
+
File.write to_file, file_content
|
56
|
+
to_file
|
57
|
+
end
|
58
|
+
|
59
|
+
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
60
|
+
# Organization Phase
|
61
|
+
|
62
|
+
# 'base modules' are modules that are permanently included on the Card or
|
63
|
+
# Format class
|
64
|
+
# 'nonbase modules' are included dynamically on singleton_classes
|
65
|
+
def process_base_modules
|
66
|
+
process_base_module_list modules[:base], Card
|
67
|
+
modules[:base_format].each do |format_class, modules_list|
|
68
|
+
process_base_module_list modules_list, format_class
|
69
|
+
end
|
70
|
+
modules.delete :base
|
71
|
+
modules.delete :base_format
|
72
|
+
end
|
73
|
+
|
74
|
+
def process_base_module_list list, klass
|
75
|
+
list.each do |mod|
|
76
|
+
klass.send :include, mod if mod.instance_methods.any?
|
77
|
+
if (class_methods = mod.const_get_if_defined(:ClassMethods))
|
78
|
+
klass.send :extend, class_methods
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def clean_empty_modules
|
84
|
+
clean_empty_module_from_hash modules[:nonbase]
|
85
|
+
modules[:nonbase_format].values.each do |hash|
|
86
|
+
clean_empty_module_from_hash hash
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def clean_empty_module_from_hash hash
|
91
|
+
hash.each do |mod_name, modlist|
|
92
|
+
modlist.delete_if { |x| x.instance_methods.empty? }
|
93
|
+
hash.delete mod_name if modlist.empty?
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
data/lib/card/set/trait.rb
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
class Card
|
2
2
|
module Set
|
3
|
-
#
|
4
3
|
# ActiveCard support: accessing plus cards as attributes
|
5
4
|
module Trait
|
6
5
|
def card_accessor *args
|
@@ -20,6 +19,11 @@ class Card
|
|
20
19
|
|
21
20
|
private
|
22
21
|
|
22
|
+
def add_attributes *args
|
23
|
+
Card.set_specific_attributes ||= []
|
24
|
+
Card.set_specific_attributes += args.map(&:to_s)
|
25
|
+
end
|
26
|
+
|
23
27
|
def get_traits mod
|
24
28
|
Card::Set.traits ||= {}
|
25
29
|
Card::Set.traits[mod] || Card::Set.traits[mod] = {}
|
@@ -27,7 +31,6 @@ class Card
|
|
27
31
|
|
28
32
|
def add_traits args, options
|
29
33
|
mod = self
|
30
|
-
# raise "Can't define card traits on all set" if mod == Card
|
31
34
|
mod_traits = get_traits mod
|
32
35
|
|
33
36
|
new_opts = options[:type] ? { type: options[:type] } : {}
|
data/lib/card/subcards.rb
CHANGED
@@ -45,22 +45,14 @@ class Card
|
|
45
45
|
end
|
46
46
|
|
47
47
|
def remove name_or_card
|
48
|
-
key =
|
49
|
-
|
50
|
-
name_or_card.key
|
51
|
-
when Symbol
|
52
|
-
fetch_subcard(name_or_card).key
|
53
|
-
else
|
54
|
-
name_or_card.to_name.key
|
55
|
-
end
|
56
|
-
|
57
|
-
key = absolutize_subcard_name(key).key unless @keys.include?(key)
|
48
|
+
key = subcard_key name_or_card
|
49
|
+
return unless @keys.include? key
|
58
50
|
@keys.delete key
|
59
51
|
removed_card = fetch_subcard key
|
60
52
|
if removed_card.current_action
|
61
53
|
removed_card.current_action.delete
|
62
54
|
end
|
63
|
-
Card::DirectorRegister.
|
55
|
+
Card::DirectorRegister.deep_delete removed_card.director
|
64
56
|
Card.cache.soft.delete key
|
65
57
|
removed_card
|
66
58
|
end
|
@@ -188,6 +180,19 @@ class Card
|
|
188
180
|
|
189
181
|
private
|
190
182
|
|
183
|
+
def subcard_key name_or_card
|
184
|
+
key = case name_or_card
|
185
|
+
when Card
|
186
|
+
name_or_card.key
|
187
|
+
when Symbol
|
188
|
+
fetch_subcard(name_or_card).key
|
189
|
+
else
|
190
|
+
name_or_card.to_name.key
|
191
|
+
end
|
192
|
+
key = absolutize_subcard_name(key).key unless @keys.include?(key)
|
193
|
+
key
|
194
|
+
end
|
195
|
+
|
191
196
|
def fetch_subcard key
|
192
197
|
Card.fetch key, local_only: true, new: {}
|
193
198
|
end
|
@@ -216,6 +221,23 @@ class Card
|
|
216
221
|
end
|
217
222
|
end
|
218
223
|
|
224
|
+
# TODO: this method already exists as card instance method in
|
225
|
+
# tracked_attributes.rb. Find a place for it where its accessible
|
226
|
+
# for both. There is one important difference. The keys are symbols
|
227
|
+
# here instead of strings
|
228
|
+
def extract_subcard_args! args
|
229
|
+
subcards = args.delete(:subcards) || {}
|
230
|
+
if (subfields = args.delete(:subfields))
|
231
|
+
subfields.each_pair do |key, value|
|
232
|
+
subcards[cardname.field(key)] = value
|
233
|
+
end
|
234
|
+
end
|
235
|
+
args.keys.each do |key|
|
236
|
+
subcards[key] = args.delete(key) if key =~ /^\+/
|
237
|
+
end
|
238
|
+
subcards
|
239
|
+
end
|
240
|
+
|
219
241
|
def new_by_attributes name, attributes={}
|
220
242
|
absolute_name = absolutize_subcard_name name
|
221
243
|
if absolute_name.field_of?(@context_card.name) &&
|
@@ -224,9 +246,13 @@ class Card
|
|
224
246
|
new_by_card left_card
|
225
247
|
left_card.new_by_attributes absolute_name, attributes
|
226
248
|
else
|
249
|
+
|
250
|
+
subcard_args = extract_subcard_args! attributes
|
227
251
|
card = Card.assign_or_initialize_by absolute_name.s, attributes,
|
228
252
|
local_only: true
|
229
|
-
new_by_card card
|
253
|
+
subcard = new_by_card card
|
254
|
+
card.subcards.add subcard_args
|
255
|
+
subcard
|
230
256
|
end
|
231
257
|
end
|
232
258
|
|
data/lib/cardio.rb
CHANGED