asset_db 0.1.0 → 0.2.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 +4 -4
- data/lib/asset_db/asset.rb +31 -0
- data/lib/asset_db/database.rb +145 -0
- data/lib/asset_db/errors.rb +18 -0
- data/lib/asset_db/group.rb +41 -0
- data/lib/asset_db/package.rb +71 -0
- data/lib/asset_db/resolver.rb +135 -0
- data/lib/asset_db/version.rb +5 -0
- data/lib/asset_db.rb +33 -0
- metadata +10 -3
- data/asset_db.gemspec +0 -27
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 42dde564b2ddc791818bc1431399d8f51a193f8e4470d157b74cb200999de40c
|
4
|
+
data.tar.gz: ce91c3dbeb2690f282f2627be18cd1c2cf9aec72012a68a0b8e97c713103d3a7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e484a766a3ab1c2845c1a1dc04e05bfc2395ca854f16945037c69597cf1a48c97b2dd7a79004a1621d4e93723ee9617d59366b71f8a0aaf0cfab1e8cc3bb10a6
|
7
|
+
data.tar.gz: 9f270d3af193419c86e44dbd78cbd3125ad95742c6b264be277c0e319a2c2175f902498484860c8a3964c9318c8ce9d5e485103a094cc762f2c47354cec56692
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'uri'
|
4
|
+
|
5
|
+
module AssetDB
|
6
|
+
class Asset
|
7
|
+
attr_reader :type, :id, :url, :metadata, :group, :package
|
8
|
+
|
9
|
+
def initialize(type:, group:, package:, url:, metadata: nil, id: url)
|
10
|
+
@type = type.to_sym
|
11
|
+
@url = url.to_s.freeze
|
12
|
+
@metadata = metadata
|
13
|
+
@id = id.to_s.freeze
|
14
|
+
@package = package
|
15
|
+
@group = group
|
16
|
+
end
|
17
|
+
|
18
|
+
def ==(other)
|
19
|
+
other.is_a?(Asset) && other.id == id
|
20
|
+
end
|
21
|
+
alias eql? ==
|
22
|
+
|
23
|
+
def hash
|
24
|
+
id.hash
|
25
|
+
end
|
26
|
+
|
27
|
+
def protocol_url?
|
28
|
+
@protocol ||= url =~ /\A[A-Za-z][A-Za-z0-9+\-.]*:\/\//
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,145 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'uri'
|
4
|
+
|
5
|
+
module AssetDB
|
6
|
+
class Database
|
7
|
+
CONFIG_RESERVED = %w[types basepath folders].freeze
|
8
|
+
|
9
|
+
attr_reader :asset_types, :basepath, :groups, :resolver
|
10
|
+
attr_accessor :separator
|
11
|
+
|
12
|
+
def initialize(asset_types: nil, basepath: nil)
|
13
|
+
@asset_types = (asset_types&.map(&:to_sym) || %i[css js]).freeze
|
14
|
+
@basepath = (basepath || '').dup
|
15
|
+
@separator = nil
|
16
|
+
@groups = {} # {id ⇒ Group}
|
17
|
+
@resolver = Resolver.new(self)
|
18
|
+
end
|
19
|
+
|
20
|
+
# DSL helpers
|
21
|
+
G_FOLDER_DEFAULT = Group::FOLDER_DEFAULT
|
22
|
+
def group(id, folder: G_FOLDER_DEFAULT, &block)
|
23
|
+
g = (@groups[id.to_s] ||= Group.new(self, id, folder: folder))
|
24
|
+
yield g if block
|
25
|
+
g
|
26
|
+
end
|
27
|
+
|
28
|
+
def groups
|
29
|
+
@groups.values
|
30
|
+
end
|
31
|
+
def asset_types
|
32
|
+
@asset_types
|
33
|
+
end
|
34
|
+
|
35
|
+
# Strict fetch for resolver
|
36
|
+
def group!(id)
|
37
|
+
@groups[id.to_s] or raise Errors::UnknownGroupError, id
|
38
|
+
end
|
39
|
+
|
40
|
+
def package!(g_id, p_id)
|
41
|
+
group!(g_id).instance_variable_get(:@packages_hash)[p_id.to_s] or
|
42
|
+
raise Errors::UnknownPackageError, "#{g_id}/#{p_id}"
|
43
|
+
end
|
44
|
+
|
45
|
+
# --------------- URL expansion ---------------
|
46
|
+
def build_url(asset)
|
47
|
+
return asset.url if asset.protocol_url?
|
48
|
+
return ensure_root_slash(asset.url) if asset.url.start_with?('/')
|
49
|
+
|
50
|
+
group = asset.group
|
51
|
+
package = asset.package
|
52
|
+
path = @basepath.dup
|
53
|
+
unless path.empty?
|
54
|
+
path.gsub!(':type', asset.type.to_s)
|
55
|
+
path.gsub!(':group', group.folder_segment.to_s)
|
56
|
+
path.gsub!(':package', package.folder_segment.to_s)
|
57
|
+
end
|
58
|
+
|
59
|
+
ensure_root_slash(File.join(path, asset.url))
|
60
|
+
end
|
61
|
+
|
62
|
+
def ensure_root_slash(pth)
|
63
|
+
('/' + pth.gsub(%r{^/+}, '')).gsub(%r{/{2,}}, '/')
|
64
|
+
end
|
65
|
+
|
66
|
+
# --------------- Config loader ---------------
|
67
|
+
def self.from_config(cfg)
|
68
|
+
cfg = cfg.transform_keys(&:to_s)
|
69
|
+
db = new(asset_types: cfg['types'], basepath: cfg['basepath'])
|
70
|
+
|
71
|
+
folders_map = (cfg['folders'] || {}).transform_keys(&:to_s).dup
|
72
|
+
if sep = folders_map.delete('separator')
|
73
|
+
db.separator = sep.to_s
|
74
|
+
end
|
75
|
+
|
76
|
+
cfg.each do |g_id, g_spec|
|
77
|
+
next if CONFIG_RESERVED.include?(g_id)
|
78
|
+
|
79
|
+
raise Errors::InvalidIdentifierError,
|
80
|
+
"group name ‘#{g_id}’ conflicts with asset type" \
|
81
|
+
if db.asset_types.include?(g_id.to_sym)
|
82
|
+
|
83
|
+
# ---------- GROUP ---------- #
|
84
|
+
if (folders_map.key? g_id)
|
85
|
+
g = db.group(g_id, folder: folders_map[g_id]) # explicit override (can be nil/false/empty)
|
86
|
+
else
|
87
|
+
g = db.group(g_id) # default ⇒ id
|
88
|
+
end
|
89
|
+
gid = g_id.to_s
|
90
|
+
|
91
|
+
# ---------- PACKAGES ---------- #
|
92
|
+
g_spec.each do |p_id, p_spec|
|
93
|
+
p_key = "#{gid}#{db.separator}#{p_id}" # composite key for folder overrides
|
94
|
+
|
95
|
+
if (folders_map.key? p_key)
|
96
|
+
pkg = g.package(p_id, folder: folders_map[p_key]) # explicit override
|
97
|
+
else
|
98
|
+
pkg = g.package(p_id) # default ⇒ id
|
99
|
+
end
|
100
|
+
|
101
|
+
p_spec.each do |k, v|
|
102
|
+
key = k.to_s
|
103
|
+
if db.asset_types.include?(key.to_sym) # ASSETS
|
104
|
+
Array(v).each { |url| pkg.asset(key, url == true ? p_id + '.' + key : url) }
|
105
|
+
else # DEPENDENCIES
|
106
|
+
Array(v).each { |target_pkg| pkg.depends_on(target_pkg, group_id: key) }
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
db
|
113
|
+
end
|
114
|
+
|
115
|
+
# Unify any number (≥2) of Package or PackageCollection into one collection
|
116
|
+
def unify(*items)
|
117
|
+
# Simple returns
|
118
|
+
if items.empty?
|
119
|
+
return nil
|
120
|
+
elsif items.size == 1
|
121
|
+
return Resolver::PackageCollection.new(self, items.first)
|
122
|
+
end
|
123
|
+
|
124
|
+
# Combine packages
|
125
|
+
merged = items.flat_map do |i|
|
126
|
+
case i
|
127
|
+
when Resolver::PackageCollection
|
128
|
+
i.instance_variable_get(:@packages)
|
129
|
+
when Package
|
130
|
+
[i]
|
131
|
+
else
|
132
|
+
raise ArgumentError, "Cannot unify #{i.inspect}"
|
133
|
+
end
|
134
|
+
end
|
135
|
+
Resolver::PackageCollection.new(self, merged)
|
136
|
+
end
|
137
|
+
|
138
|
+
def validate_identifier!(name)
|
139
|
+
if separator && name.to_s.include?(separator)
|
140
|
+
raise Errors::InvalidIdentifierError, "'#{separator}' forbidden in identifier #{name.inspect}"
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
end
|
145
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AssetDB
|
4
|
+
module Errors
|
5
|
+
class AssetDBError < StandardError; end
|
6
|
+
class UnknownGroupError < AssetDBError; end
|
7
|
+
class UnknownPackageError < AssetDBError; end
|
8
|
+
class CycleError < AssetDBError
|
9
|
+
attr_reader :cycle
|
10
|
+
def initialize(cycle)
|
11
|
+
@cycle = cycle
|
12
|
+
super("Dependency cycle detected: " +
|
13
|
+
cycle.map { |p| "#{p.group.id}:#{p.id}" }.join(' → '))
|
14
|
+
end
|
15
|
+
end
|
16
|
+
class InvalidIdentifierError < AssetDBError; end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AssetDB
|
4
|
+
class Group
|
5
|
+
FOLDER_DEFAULT = :__default
|
6
|
+
|
7
|
+
attr_reader :database, :id
|
8
|
+
|
9
|
+
def initialize(database, id, folder: FOLDER_DEFAULT)
|
10
|
+
database.validate_identifier!(id)
|
11
|
+
@database = database
|
12
|
+
@id = id.to_s
|
13
|
+
@folder = folder.equal?(FOLDER_DEFAULT) ? FOLDER_DEFAULT : folder
|
14
|
+
@packages_hash = {} # {id ⇒ Package}
|
15
|
+
end
|
16
|
+
|
17
|
+
# DSL – fetch or create.
|
18
|
+
def package(id, folder: FOLDER_DEFAULT, &block)
|
19
|
+
pkg = (@packages_hash[id.to_s] ||= Package.new(self, id, folder: folder))
|
20
|
+
yield pkg if block
|
21
|
+
pkg
|
22
|
+
end
|
23
|
+
|
24
|
+
def packages
|
25
|
+
@packages_hash.values
|
26
|
+
end
|
27
|
+
def package_ids
|
28
|
+
@packages_hash.keys
|
29
|
+
end
|
30
|
+
def folder_spec
|
31
|
+
@folder
|
32
|
+
end
|
33
|
+
|
34
|
+
def folder_segment
|
35
|
+
return id if @folder.equal?(FOLDER_DEFAULT)
|
36
|
+
return nil if !@folder || @folder == '' || @folder == false
|
37
|
+
@folder.to_s
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AssetDB
|
4
|
+
class Package
|
5
|
+
FOLDER_DEFAULT = :__default
|
6
|
+
|
7
|
+
attr_reader :id, :group
|
8
|
+
|
9
|
+
def initialize(group, id, folder: FOLDER_DEFAULT)
|
10
|
+
@group = group
|
11
|
+
database.validate_identifier!(id)
|
12
|
+
@id = id.to_s
|
13
|
+
@folder = folder.equal?(FOLDER_DEFAULT) ? FOLDER_DEFAULT : folder
|
14
|
+
@assets = Hash.new { |h, k| h[k] = [] } # {type ⇒ [Asset]}
|
15
|
+
@dependencies = [] # [[group_id, package_id]]
|
16
|
+
@cache = {} # {type|:all ⇒ …}
|
17
|
+
end
|
18
|
+
|
19
|
+
def asset(type, url, metadata = nil, id: url)
|
20
|
+
type = type.to_sym
|
21
|
+
check_type!(type)
|
22
|
+
@assets[type] << Asset.new(type: type, url: url, group: group, package: self, metadata: metadata, id: id)
|
23
|
+
invalidate_cache
|
24
|
+
self
|
25
|
+
end
|
26
|
+
|
27
|
+
def depends_on(pkg_id, group_id: group.id)
|
28
|
+
@dependencies << [group_id.to_s, pkg_id.to_s]
|
29
|
+
invalidate_cache
|
30
|
+
self
|
31
|
+
end
|
32
|
+
|
33
|
+
def resolved_assets(type = nil)
|
34
|
+
key = type ? type.to_sym : :all
|
35
|
+
@cache[key] ||= database.resolver.resolve(self, type: type&.to_sym)
|
36
|
+
end
|
37
|
+
|
38
|
+
def +(other)
|
39
|
+
database.unify(self, other)
|
40
|
+
end
|
41
|
+
|
42
|
+
def folder_segment
|
43
|
+
return id if @folder.equal?(FOLDER_DEFAULT)
|
44
|
+
return nil if !@folder || @folder == '' || @folder == false
|
45
|
+
@folder.to_s
|
46
|
+
end
|
47
|
+
|
48
|
+
def assets
|
49
|
+
@assets
|
50
|
+
end
|
51
|
+
def dependencies
|
52
|
+
@dependencies
|
53
|
+
end
|
54
|
+
def key?
|
55
|
+
"#{group.id}/#{id}".freeze
|
56
|
+
end
|
57
|
+
def database
|
58
|
+
group.database
|
59
|
+
end
|
60
|
+
|
61
|
+
private
|
62
|
+
|
63
|
+
def invalidate_cache
|
64
|
+
@cache.clear
|
65
|
+
end
|
66
|
+
def check_type!(t)
|
67
|
+
database.asset_types.include?(t) or raise ArgumentError, "Unknown type #{t}"
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,135 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'set'
|
4
|
+
|
5
|
+
module AssetDB
|
6
|
+
class Resolver
|
7
|
+
def initialize(database)
|
8
|
+
@database = database
|
9
|
+
@memo = {} # {pkg_key ⇒ {type|:all ⇒ result}}
|
10
|
+
@mutex = Mutex.new
|
11
|
+
end
|
12
|
+
|
13
|
+
def resolve(pkg, type: nil)
|
14
|
+
type_key = type ? type.to_sym : :all
|
15
|
+
@mutex.synchronize { (@memo[pkg.key?] ||= {})[type_key] ||= (type ? dfs_type(pkg, type_key) : dfs_all(pkg)) }
|
16
|
+
end
|
17
|
+
|
18
|
+
# --------------------------------------------------
|
19
|
+
# private helpers
|
20
|
+
# --------------------------------------------------
|
21
|
+
private
|
22
|
+
|
23
|
+
def dfs_type(pkg, type, visiting = Set.new, stack = [])
|
24
|
+
return @memo.dig(pkg.key?, type) if @memo.dig(pkg.key?, type)
|
25
|
+
|
26
|
+
raise Errors::CycleError.new(stack + [pkg]) if visiting.include?(pkg.key?)
|
27
|
+
visiting.add(pkg.key?); stack.push(pkg)
|
28
|
+
|
29
|
+
ordered = []
|
30
|
+
seen_ids = Set.new
|
31
|
+
|
32
|
+
pkg.dependencies.each do |(g_id, p_id)|
|
33
|
+
dep_pkg = @database.package!(g_id, p_id)
|
34
|
+
dfs_type(dep_pkg, type, visiting, stack).each do |asset|
|
35
|
+
next if seen_ids.include?(asset.id)
|
36
|
+
seen_ids << asset.id
|
37
|
+
ordered << asset
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
pkg.assets[type].each do |asset|
|
42
|
+
next if seen_ids.include?(asset.id)
|
43
|
+
seen_ids << asset.id
|
44
|
+
ordered << asset
|
45
|
+
end
|
46
|
+
|
47
|
+
stack.pop; visiting.delete(pkg.key?)
|
48
|
+
ordered.freeze
|
49
|
+
end
|
50
|
+
|
51
|
+
def dfs_all(pkg, visiting = Set.new, stack = [])
|
52
|
+
return @memo.dig(pkg.key?, :all) if @memo.dig(pkg.key?, :all)
|
53
|
+
|
54
|
+
raise Errors::CycleError.new(stack + [pkg]) if visiting.include?(pkg.key?)
|
55
|
+
visiting.add(pkg.key?); stack.push(pkg)
|
56
|
+
|
57
|
+
result = Hash.new { |h, k| h[k] = [] }
|
58
|
+
seen = Hash.new { |h, k| h[k] = Set.new }
|
59
|
+
|
60
|
+
pkg.dependencies.each do |(g_id, p_id)|
|
61
|
+
dep_pkg = @database.package!(g_id, p_id)
|
62
|
+
dfs_all(dep_pkg, visiting, stack).each do |t, assets|
|
63
|
+
assets.each do |asset|
|
64
|
+
next if seen[t].include?(asset.id)
|
65
|
+
seen[t] << asset.id
|
66
|
+
result[t] << asset
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
pkg.assets.each do |t, assets|
|
72
|
+
assets.each do |asset|
|
73
|
+
next if seen[t].include?(asset.id)
|
74
|
+
seen[t] << asset.id
|
75
|
+
result[t] << asset
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
stack.pop; visiting.delete(pkg.key?)
|
80
|
+
result.transform_values!(&:freeze).freeze
|
81
|
+
end
|
82
|
+
|
83
|
+
# --------------------------------------------------
|
84
|
+
# lightweight immutable union façade
|
85
|
+
# --------------------------------------------------
|
86
|
+
class PackageCollection
|
87
|
+
include Enumerable
|
88
|
+
|
89
|
+
def initialize(database, pkgs)
|
90
|
+
@database = database
|
91
|
+
@packages = Array(pkgs).uniq
|
92
|
+
@cache = {} # {[type, key] ⇒ [Asset]}
|
93
|
+
end
|
94
|
+
|
95
|
+
def +(other)
|
96
|
+
@database.unify(self, other)
|
97
|
+
end
|
98
|
+
|
99
|
+
def each_asset(type = nil, &block)
|
100
|
+
return @database.asset_types.each { |t| each_asset(t, &block) } if type.nil?
|
101
|
+
|
102
|
+
type = type.to_sym
|
103
|
+
key = [type, @packages.map(&:key?).sort].hash
|
104
|
+
@cache[key] ||= begin
|
105
|
+
seen = Set.new
|
106
|
+
arr = []
|
107
|
+
@packages.each do |pkg|
|
108
|
+
pkg.resolved_assets(type).each do |asset|
|
109
|
+
next if seen.include?(asset.id)
|
110
|
+
seen << asset.id
|
111
|
+
arr << asset
|
112
|
+
end
|
113
|
+
end
|
114
|
+
arr.freeze
|
115
|
+
end
|
116
|
+
block ? @cache[key].each(&block) : @cache[key]
|
117
|
+
end
|
118
|
+
|
119
|
+
def each
|
120
|
+
return to_enum(:each) unless block_given?
|
121
|
+
|
122
|
+
seen = Set.new
|
123
|
+
@database.asset_types.each do |type|
|
124
|
+
each_asset(type).each do |asset|
|
125
|
+
next if seen.include?(asset.id) # de-dupe across types just in case
|
126
|
+
seen << asset.id
|
127
|
+
yield asset
|
128
|
+
end
|
129
|
+
end
|
130
|
+
self
|
131
|
+
end
|
132
|
+
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
data/lib/asset_db.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'set'
|
4
|
+
|
5
|
+
# version must come first so errors, etc. have a version constant available
|
6
|
+
require_relative 'asset_db/version'
|
7
|
+
require_relative 'asset_db/errors'
|
8
|
+
require_relative 'asset_db/asset'
|
9
|
+
require_relative 'asset_db/group'
|
10
|
+
require_relative 'asset_db/package'
|
11
|
+
require_relative 'asset_db/resolver'
|
12
|
+
require_relative 'asset_db/database'
|
13
|
+
|
14
|
+
module AssetDB
|
15
|
+
# DSL entry point, e.g.
|
16
|
+
#
|
17
|
+
# db = AssetDB.build(types: %i[css js], basepath: '/assets/:type/:group/:package') do |d|
|
18
|
+
# # ...
|
19
|
+
# end
|
20
|
+
def self.build(types: nil, basepath: nil, &block)
|
21
|
+
db = Database.new(asset_types: types, basepath: basepath)
|
22
|
+
yield db if block
|
23
|
+
db
|
24
|
+
end
|
25
|
+
|
26
|
+
# Configuration-driven constructor:
|
27
|
+
#
|
28
|
+
# db = AssetDB.load(config_hash)
|
29
|
+
#
|
30
|
+
def self.load(config)
|
31
|
+
Database.from_config(config)
|
32
|
+
end
|
33
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: asset_db
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Convincible Media
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-08-
|
11
|
+
date: 2025-08-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -60,7 +60,14 @@ executables: []
|
|
60
60
|
extensions: []
|
61
61
|
extra_rdoc_files: []
|
62
62
|
files:
|
63
|
-
- asset_db.
|
63
|
+
- lib/asset_db.rb
|
64
|
+
- lib/asset_db/asset.rb
|
65
|
+
- lib/asset_db/database.rb
|
66
|
+
- lib/asset_db/errors.rb
|
67
|
+
- lib/asset_db/group.rb
|
68
|
+
- lib/asset_db/package.rb
|
69
|
+
- lib/asset_db/resolver.rb
|
70
|
+
- lib/asset_db/version.rb
|
64
71
|
homepage: https://github.com/ConvincibleMedia/ruby-gem-assetdb
|
65
72
|
licenses:
|
66
73
|
- MIT
|
data/asset_db.gemspec
DELETED
@@ -1,27 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
require_relative 'lib/asset_db/version'
|
3
|
-
|
4
|
-
Gem::Specification.new do |spec|
|
5
|
-
spec.name = 'asset_db'
|
6
|
-
spec.version = AssetDB::VERSION
|
7
|
-
spec.authors = ['Convincible Media']
|
8
|
-
spec.email = ['development@convincible.media']
|
9
|
-
|
10
|
-
spec.summary = "Lightweight asset dependency database for Ruby"
|
11
|
-
spec.description = "Provides a structured way to define, organise, and resolve assets (CSS, JS, etc.) and their interdependencies across packages and groups."
|
12
|
-
spec.homepage = 'https://github.com/ConvincibleMedia/ruby-gem-assetdb'
|
13
|
-
spec.license = 'MIT'
|
14
|
-
|
15
|
-
spec.required_ruby_version = '>= 2.4'
|
16
|
-
|
17
|
-
# Files to include in the gem
|
18
|
-
spec.files = Dir.chdir(__dir__) do
|
19
|
-
`git ls-files -z`.split("\x0").grep(%r{\A(?:lib|README\.md|LICENSE|asset_db\.gemspec)\z})
|
20
|
-
end
|
21
|
-
|
22
|
-
# No runtime dependencies
|
23
|
-
# Development dependencies
|
24
|
-
spec.add_development_dependency 'bundler', '~> 2.0'
|
25
|
-
spec.add_development_dependency 'rake', '~> 13.0'
|
26
|
-
spec.add_development_dependency 'rspec', '~> 3.0'
|
27
|
-
end
|