parcels 0.0.1

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.
Files changed (158) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +22 -0
  3. data/.rspec-local +4 -0
  4. data/.travis.yml +54 -0
  5. data/Gemfile +6 -0
  6. data/LICENSE.txt +22 -0
  7. data/README.md +29 -0
  8. data/Rakefile +6 -0
  9. data/lib/parcels/dependency_parcel_list.rb +50 -0
  10. data/lib/parcels/environment.rb +60 -0
  11. data/lib/parcels/fortitude/alongside_engine.rb +37 -0
  12. data/lib/parcels/fortitude/assets.rb +212 -0
  13. data/lib/parcels/fortitude/enabling.rb +72 -0
  14. data/lib/parcels/fortitude/fortitude_engine.rb +35 -0
  15. data/lib/parcels/fortitude/fortitude_loader.rb +27 -0
  16. data/lib/parcels/fortitude/widget_engine.rb +31 -0
  17. data/lib/parcels/fortitude_alongside_parcel.rb +38 -0
  18. data/lib/parcels/fortitude_inline_parcel.rb +31 -0
  19. data/lib/parcels/fortitude_parcel.rb +102 -0
  20. data/lib/parcels/fragments/css_fragment.rb +107 -0
  21. data/lib/parcels/index.rb +16 -0
  22. data/lib/parcels/rails/rails_loader.rb +23 -0
  23. data/lib/parcels/rails/railtie.rb +16 -0
  24. data/lib/parcels/sprockets.rb +153 -0
  25. data/lib/parcels/utils/path_utils.rb +32 -0
  26. data/lib/parcels/version.rb +3 -0
  27. data/lib/parcels/widget_tree.rb +158 -0
  28. data/lib/parcels.rb +21 -0
  29. data/parcels.gemspec +48 -0
  30. data/spec/helpers/content_in_helpers.rb +21 -0
  31. data/spec/helpers/file_structure_helpers.rb +79 -0
  32. data/spec/helpers/global_helper.rb +34 -0
  33. data/spec/helpers/new_asset_helpers.rb +31 -0
  34. data/spec/helpers/new_rails_helpers.rb +31 -0
  35. data/spec/helpers/parcels_rails_helpers.rb +20 -0
  36. data/spec/helpers/per_example_helpers.rb +15 -0
  37. data/spec/helpers/sprockets_helpers.rb +23 -0
  38. data/spec/lib/spec/expected/base_expected_asset.rb +35 -0
  39. data/spec/lib/spec/expected/expected_asset.rb +135 -0
  40. data/spec/lib/spec/expected/expected_asset_set.rb +45 -0
  41. data/spec/lib/spec/expected/must_not_be_present_asset.rb +17 -0
  42. data/spec/lib/spec/fixtures/file_set.rb +80 -0
  43. data/spec/lib/spec/fixtures/widget_base.rb +13 -0
  44. data/spec/lib/spec/fixtures/widget_file.rb +108 -0
  45. data/spec/lib/spec/parsing/compiled_asset.rb +94 -0
  46. data/spec/lib/spec/parsing/compiled_asset_fragment.rb +38 -0
  47. data/spec/lib/spec/parsing/parsed_css_asset.rb +34 -0
  48. data/spec/lib/spec/parsing/precompiled_rails_asset.rb +52 -0
  49. data/spec/lib/spec/parsing/rails_asset.rb +30 -0
  50. data/spec/lib/spec/parsing/sprockets_asset.rb +40 -0
  51. data/spec/rails/basic_rails_spec.rb +102 -0
  52. data/spec/rails/compression_rails_spec.rb +11 -0
  53. data/spec/rails/development_mode_rails_spec.rb +321 -0
  54. data/spec/rails/sass_rails_spec.rb +125 -0
  55. data/spec/rails/sets_rails_spec.rb +85 -0
  56. data/spec/rails/templates/base/app/assets/stylesheets/application.css +16 -0
  57. data/spec/rails/templates/base/app/views/widgets/base.rb +4 -0
  58. data/spec/rails/templates/base/config/environments/production.rb +92 -0
  59. data/spec/rails/templates/base/lib/null_compressor.rb +5 -0
  60. data/spec/rails/templates/basic_rails_spec/app/controllers/basic_rails_spec_controller.rb +21 -0
  61. data/spec/rails/templates/basic_rails_spec/app/views/basic_rails_spec/alongside_and_inline.pcss +1 -0
  62. data/spec/rails/templates/basic_rails_spec/app/views/basic_rails_spec/alongside_and_inline.rb +9 -0
  63. data/spec/rails/templates/basic_rails_spec/app/views/basic_rails_spec/alongside_and_inline_html.html.pcss +1 -0
  64. data/spec/rails/templates/basic_rails_spec/app/views/basic_rails_spec/alongside_and_inline_html.html.rb +9 -0
  65. data/spec/rails/templates/basic_rails_spec/app/views/basic_rails_spec/alongside_erb.pcss +1 -0
  66. data/spec/rails/templates/basic_rails_spec/app/views/basic_rails_spec/alongside_erb.rb +7 -0
  67. data/spec/rails/templates/basic_rails_spec/app/views/basic_rails_spec/inline_erb.rb +9 -0
  68. data/spec/rails/templates/basic_rails_spec/app/views/basic_rails_spec/multiple_engines.pcss +1 -0
  69. data/spec/rails/templates/basic_rails_spec/app/views/basic_rails_spec/multiple_engines.rb +9 -0
  70. data/spec/rails/templates/basic_rails_spec/app/views/basic_rails_spec/no_corresponding_widget.pcss +1 -0
  71. data/spec/rails/templates/basic_rails_spec/app/views/basic_rails_spec/simple_css.rb +9 -0
  72. data/spec/rails/templates/compression_rails_spec/app/controllers/compression_rails_spec_controller.rb +5 -0
  73. data/spec/rails/templates/compression_rails_spec/app/views/compression_rails_spec/inline_and_alongside_css.pcss +1 -0
  74. data/spec/rails/templates/compression_rails_spec/app/views/compression_rails_spec/inline_and_alongside_css.rb +9 -0
  75. data/spec/rails/templates/compression_rails_spec/config/environments/production.rb +91 -0
  76. data/spec/rails/templates/development_mode_rails_spec/app/assets/stylesheets/changingone.scss +1 -0
  77. data/spec/rails/templates/development_mode_rails_spec/app/assets/stylesheets/changingtwo.scss +1 -0
  78. data/spec/rails/templates/development_mode_rails_spec/app/assets/stylesheets/import_dir/import_dir_ss_1.scss +1 -0
  79. data/spec/rails/templates/development_mode_rails_spec/app/controllers/development_mode_rails_spec_controller.rb +45 -0
  80. data/spec/rails/templates/development_mode_rails_spec/app/views/development_mode_rails_spec/adding_alongside_css.rb +5 -0
  81. data/spec/rails/templates/development_mode_rails_spec/app/views/development_mode_rails_spec/adding_inline_css.rb +7 -0
  82. data/spec/rails/templates/development_mode_rails_spec/app/views/development_mode_rails_spec/adding_widget.rb +5 -0
  83. data/spec/rails/templates/development_mode_rails_spec/app/views/development_mode_rails_spec/basic_widget_with_inline_and_alongside_parcels.pcss +3 -0
  84. data/spec/rails/templates/development_mode_rails_spec/app/views/development_mode_rails_spec/basic_widget_with_inline_and_alongside_parcels.rb +9 -0
  85. data/spec/rails/templates/development_mode_rails_spec/app/views/development_mode_rails_spec/changing_alongside_css.pcss +1 -0
  86. data/spec/rails/templates/development_mode_rails_spec/app/views/development_mode_rails_spec/changing_alongside_css.rb +5 -0
  87. data/spec/rails/templates/development_mode_rails_spec/app/views/development_mode_rails_spec/changing_import_file.pcss +2 -0
  88. data/spec/rails/templates/development_mode_rails_spec/app/views/development_mode_rails_spec/changing_import_file.rb +10 -0
  89. data/spec/rails/templates/development_mode_rails_spec/app/views/development_mode_rails_spec/changing_inline_css.rb +9 -0
  90. data/spec/rails/templates/development_mode_rails_spec/app/views/development_mode_rails_spec/changing_prefix_imported_file.pcss +1 -0
  91. data/spec/rails/templates/development_mode_rails_spec/app/views/development_mode_rails_spec/changing_prefix_imported_file.rb +7 -0
  92. data/spec/rails/templates/development_mode_rails_spec/app/views/development_mode_rails_spec/removing_alongside_css.pcss +1 -0
  93. data/spec/rails/templates/development_mode_rails_spec/app/views/development_mode_rails_spec/removing_alongside_css.rb +5 -0
  94. data/spec/rails/templates/development_mode_rails_spec/app/views/development_mode_rails_spec/removing_inline_css.rb +7 -0
  95. data/spec/rails/templates/development_mode_rails_spec/app/views/development_mode_rails_spec/removing_widget.pcss +1 -0
  96. data/spec/rails/templates/development_mode_rails_spec/app/views/development_mode_rails_spec/removing_widget.rb +9 -0
  97. data/spec/rails/templates/development_mode_rails_spec/app/views/import_base.rb +5 -0
  98. data/spec/rails/templates/development_mode_rails_spec/config/environments/development.rb +37 -0
  99. data/spec/rails/templates/development_mode_rails_spec/vendor/assets/stylesheets/one.scss +1 -0
  100. data/spec/rails/templates/development_mode_rails_spec/vendor/assets/stylesheets/two.scss +1 -0
  101. data/spec/rails/templates/sass_rails_spec/app/assets/foobar/the_import_dir_2/id2ss1.scss +1 -0
  102. data/spec/rails/templates/sass_rails_spec/app/assets/foobar/the_import_dir_2/id2ss2.scss +1 -0
  103. data/spec/rails/templates/sass_rails_spec/app/assets/foobar/twelve.scss +1 -0
  104. data/spec/rails/templates/sass_rails_spec/app/assets/foobar/two.scss +1 -0
  105. data/spec/rails/templates/sass_rails_spec/app/assets/images/quux/foo.png +0 -0
  106. data/spec/rails/templates/sass_rails_spec/app/assets/stylesheets/eleven.scss +1 -0
  107. data/spec/rails/templates/sass_rails_spec/app/assets/stylesheets/one.scss +1 -0
  108. data/spec/rails/templates/sass_rails_spec/app/assets/stylesheets/shared_import_dir/sid1ss1.scss +1 -0
  109. data/spec/rails/templates/sass_rails_spec/app/assets/stylesheets/shared_import_dir/sid1ss2.scss +1 -0
  110. data/spec/rails/templates/sass_rails_spec/app/assets/stylesheets/the_import_dir_1/id1ss1.scss +1 -0
  111. data/spec/rails/templates/sass_rails_spec/app/assets/stylesheets/the_import_dir_1/id1ss2.scss +1 -0
  112. data/spec/rails/templates/sass_rails_spec/app/controllers/sass_rails_spec_controller.rb +29 -0
  113. data/spec/rails/templates/sass_rails_spec/app/views/sass_rails_spec/added_asset_path.pcss +2 -0
  114. data/spec/rails/templates/sass_rails_spec/app/views/sass_rails_spec/added_asset_path.rb +10 -0
  115. data/spec/rails/templates/sass_rails_spec/app/views/sass_rails_spec/asset_url.pcss +2 -0
  116. data/spec/rails/templates/sass_rails_spec/app/views/sass_rails_spec/asset_url.rb +17 -0
  117. data/spec/rails/templates/sass_rails_spec/app/views/sass_rails_spec/default_sass_import.pcss +6 -0
  118. data/spec/rails/templates/sass_rails_spec/app/views/sass_rails_spec/default_sass_import.rb +14 -0
  119. data/spec/rails/templates/sass_rails_spec/app/views/sass_rails_spec/import_directory.pcss +3 -0
  120. data/spec/rails/templates/sass_rails_spec/app/views/sass_rails_spec/import_directory.rb +11 -0
  121. data/spec/rails/templates/sass_rails_spec/app/views/sass_rails_spec/import_view_relative_directory.pcss +3 -0
  122. data/spec/rails/templates/sass_rails_spec/app/views/sass_rails_spec/import_view_relative_directory.rb +11 -0
  123. data/spec/rails/templates/sass_rails_spec/app/views/sass_rails_spec/other_features.pcss +1 -0
  124. data/spec/rails/templates/sass_rails_spec/app/views/sass_rails_spec/other_features.rb +9 -0
  125. data/spec/rails/templates/sass_rails_spec/app/views/sass_rails_spec/shared_imports.rb +10 -0
  126. data/spec/rails/templates/sass_rails_spec/app/views/sass_rails_spec/vr_import_dir_1/vr1ss1.scss +1 -0
  127. data/spec/rails/templates/sass_rails_spec/app/views/sass_rails_spec/vr_import_dir_1/vr1ss2.scss +1 -0
  128. data/spec/rails/templates/sass_rails_spec/app/views/sass_rails_spec/vr_import_dir_2/vr2ss1.scss +1 -0
  129. data/spec/rails/templates/sass_rails_spec/app/views/sass_rails_spec/vr_import_dir_2/vr2ss2.scss +1 -0
  130. data/spec/rails/templates/sass_rails_spec/app/views/widgets/import_base.rb +5 -0
  131. data/spec/rails/templates/sass_rails_spec/config/application.rb +25 -0
  132. data/spec/rails/templates/sass_rails_spec/lib/more_assets/twenty.scss +1 -0
  133. data/spec/rails/templates/sass_rails_spec/vendor/assets/stylesheets/thirteen.scss +1 -0
  134. data/spec/rails/templates/sass_rails_spec/vendor/assets/stylesheets/three.scss +1 -0
  135. data/spec/rails/templates/sets_rails_spec/app/assets/stylesheets/admin.css.scss +1 -0
  136. data/spec/rails/templates/sets_rails_spec/app/assets/stylesheets/all.css.scss +1 -0
  137. data/spec/rails/templates/sets_rails_spec/app/assets/stylesheets/normal.css.scss +1 -0
  138. data/spec/rails/templates/sets_rails_spec/app/controllers/sets_rails_spec_controller.rb +3 -0
  139. data/spec/rails/templates/sets_rails_spec/app/views/admin/admin_one.pcss +1 -0
  140. data/spec/rails/templates/sets_rails_spec/app/views/admin/admin_one.rb +3 -0
  141. data/spec/rails/templates/sets_rails_spec/app/views/admin/admin_two.pcss +1 -0
  142. data/spec/rails/templates/sets_rails_spec/app/views/admin/admin_two.rb +3 -0
  143. data/spec/rails/templates/sets_rails_spec/app/views/admin/base.rb +3 -0
  144. data/spec/rails/templates/sets_rails_spec/app/views/root.rb +9 -0
  145. data/spec/rails/templates/sets_rails_spec/app/views/sets_base.rb +3 -0
  146. data/spec/rails/templates/sets_rails_spec/app/views/sets_rails_spec/normal_one.pcss +1 -0
  147. data/spec/rails/templates/sets_rails_spec/app/views/sets_rails_spec/normal_one.rb +3 -0
  148. data/spec/rails/templates/sets_rails_spec/app/views/sets_rails_spec/normal_two.pcss +1 -0
  149. data/spec/rails/templates/sets_rails_spec/app/views/sets_rails_spec/normal_two.rb +3 -0
  150. data/spec/system/alongside_file_spec.rb +193 -0
  151. data/spec/system/autogenerated_class_application_spec.rb +240 -0
  152. data/spec/system/basic_system_spec.rb +75 -0
  153. data/spec/system/dependency_sorting_spec.rb +48 -0
  154. data/spec/system/engines_spec.rb +245 -0
  155. data/spec/system/prefix_spec.rb +108 -0
  156. data/spec/system/sass_features_spec.rb +109 -0
  157. data/spec/system/sets_spec.rb +405 -0
  158. metadata +477 -0
@@ -0,0 +1,38 @@
1
+ require 'parcels/fortitude_parcel'
2
+
3
+ require 'parcels/utils/path_utils'
4
+
5
+ module Parcels
6
+ class FortitudeAlongsideParcel < FortitudeParcel
7
+ def self.logical_path_prefix
8
+ "#{logical_path_prefix_base}alongside"
9
+ end
10
+
11
+ def to_css(sprockets_context)
12
+ if widget_class.respond_to?(:_parcels_widget_class_alongside_css) &&
13
+ (!(css = widget_class._parcels_widget_class_alongside_css(widget_tree.parcels_environment, sprockets_context)).blank?)
14
+ css
15
+ end
16
+ end
17
+
18
+ def tag_types_that_must_come_before
19
+ [ ]
20
+ end
21
+
22
+ def tag_type
23
+ :alongside
24
+ end
25
+
26
+ def usable?
27
+ widget_class_full_path
28
+ end
29
+
30
+ private
31
+ attr_reader :widget_tree, :full_path
32
+
33
+ def widget_class_full_path
34
+ @widget_class_full_path ||= (::Parcels::Utils::PathUtils.widget_class_file_for_alongside_file(full_path) || :none)
35
+ @widget_class_full_path unless @widget_class_full_path == :none
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,31 @@
1
+ require 'parcels/fortitude_parcel'
2
+
3
+ module Parcels
4
+ class FortitudeInlineParcel < FortitudeParcel
5
+ def self.logical_path_prefix
6
+ "#{logical_path_prefix_base}inline"
7
+ end
8
+
9
+ def to_css(sprockets_context)
10
+ if widget_class.respond_to?(:_parcels_widget_class_inline_css) &&
11
+ (!(css = widget_class._parcels_widget_class_inline_css(widget_tree.parcels_environment, sprockets_context)).blank?)
12
+ css
13
+ end
14
+ end
15
+
16
+ def tag_type
17
+ :inline
18
+ end
19
+
20
+ def tag_types_that_must_come_before
21
+ [ :alongside ]
22
+ end
23
+
24
+ private
25
+ attr_reader :widget_tree, :full_path
26
+
27
+ def widget_class_full_path
28
+ full_path
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,102 @@
1
+ require 'active_support/core_ext/module/delegation'
2
+
3
+ require 'parcels/utils/path_utils'
4
+
5
+ module Parcels
6
+ class FortitudeParcel
7
+ def self.logical_path_prefix_base
8
+ "_parcels_"
9
+ end
10
+
11
+ def self.is_fortitude_logical_path?(logical_path)
12
+ logical_path =~ /^#{Regexp.escape(logical_path_prefix_base)}/
13
+ end
14
+
15
+ def initialize(widget_tree, full_path)
16
+ @widget_tree = widget_tree
17
+ @full_path = full_path
18
+ end
19
+
20
+ def to_s
21
+ "<#{self.class.name.demodulize} for #{widget_class}>"
22
+ end
23
+
24
+ def inspect
25
+ "<#{self.class.name.demodulize} for #{widget_class}, tree #{widget_tree}>"
26
+ end
27
+
28
+ def usable?
29
+ true
30
+ end
31
+
32
+ def included_in_any_set?(set_names)
33
+ if set_names.length == 0
34
+ true
35
+ else
36
+ result = (widget_class._parcels_get_sets(full_path) & set_names)
37
+ result.length > 0
38
+ end
39
+ end
40
+
41
+ def add_to_sprockets_context!(sprockets_context)
42
+ if has_content?(sprockets_context)
43
+ sprockets_context.require_asset(logical_path)
44
+ else
45
+ sprockets_context.depend_on_asset(logical_path)
46
+ end
47
+ end
48
+
49
+ def tag
50
+ [ tag_type, widget_class ]
51
+ end
52
+
53
+ def tags_that_must_come_before
54
+ out = tag_types_that_must_come_before.map { |tt| [ tt, widget_class ] }
55
+ widget_class.all_fortitude_superclasses.each do |superclass|
56
+ all_tag_types.each do |tt|
57
+ out << [ tt, superclass ]
58
+ end
59
+ end
60
+ out
61
+ end
62
+
63
+ def all_tag_types
64
+ [ :alongside, :inline ]
65
+ end
66
+
67
+ def tag_type
68
+ raise "must implement in #{self.class.name}"
69
+ end
70
+
71
+ def tag_types_that_must_come_before
72
+ raise "must implement in #{self.class.name}"
73
+ end
74
+
75
+ def to_css(sprockets_context)
76
+ raise "must implement in #{self.class.name}"
77
+ end
78
+
79
+ private
80
+ attr_reader :widget_tree, :full_path
81
+
82
+ def has_content?(sprockets_context)
83
+ !! to_css(sprockets_context)
84
+ end
85
+
86
+ def subpath
87
+ @subpath ||= widget_tree.subpath_to(full_path)
88
+ end
89
+
90
+ def logical_path
91
+ @logical_path ||= File.join(self.class.logical_path_prefix, subpath)
92
+ end
93
+
94
+ def widget_class_full_path
95
+ raise "must implement in #{self.class.name}"
96
+ end
97
+
98
+ def widget_class
99
+ @widget_class ||= ::Fortitude::Widget.widget_class_from_file(widget_class_full_path, :root_dirs => [ widget_tree.root ])
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,107 @@
1
+ module Parcels
2
+ module Fragments
3
+ class CssFragment
4
+ class << self
5
+ def to_css(parcels_environment, context, fragments)
6
+ fragments = Array(fragments)
7
+ fragments.map { |f| f.to_css(parcels_environment, context) }.join("\n")
8
+ end
9
+ end
10
+
11
+ def initialize(css_string, source, file, line, options)
12
+ options.assert_valid_keys(:engines, :wrap, :prefix)
13
+
14
+ @css_string = css_string
15
+ @source = source
16
+ @file = file
17
+ @line = line
18
+ @options = options
19
+ end
20
+
21
+ def wrapping_css_class_required?
22
+ wrapped?
23
+ end
24
+
25
+ def to_s
26
+ "<#{self.class.name.demodulize}: from '#{file}', line #{line}, options #{options.inspect}>"
27
+ end
28
+
29
+ def to_css(parcels_environment, context)
30
+ scss = css_string
31
+
32
+ if wrapped? && (wrapper_css_class = source.try(:_parcels_widget_outer_element_class))
33
+ scss = %{.#{wrapper_css_class} {
34
+ #{scss}
35
+ }}
36
+ end
37
+
38
+ if options[:prefix]
39
+ if options[:prefix].kind_of?(String)
40
+ scss = "#{options[:prefix]}\n\n#{scss}"
41
+ else
42
+ raise "You supplied a css_prefix (or a :prefix option) that wasn't a String, but, rather: #{options[:prefix].inspect}"
43
+ end
44
+ end
45
+
46
+ asset_attributes = ::Sprockets::AssetAttributes.new(parcels_environment.sprockets_environment, synthetic_filename)
47
+ processors = asset_attributes.processors
48
+ out = process_with_processors(processors, context, scss)
49
+
50
+ header_comment + out
51
+ end
52
+
53
+ private
54
+ attr_reader :css_string, :source, :options, :file, :line
55
+
56
+ def header_comment
57
+ out = "/* From '#{file}'"
58
+ out << ":#{line}" if line
59
+ out << " */\n"
60
+ out
61
+ end
62
+
63
+ def wrapped?
64
+ options.fetch(:wrap, true)
65
+ end
66
+
67
+ def synthetic_filename
68
+ @synthetic_filename ||= begin
69
+ synthetic_name = File.basename(file)
70
+ synthetic_name = $1 if synthetic_name =~ /^([^\.]+)\./i
71
+ synthetic_name << ".css.scss"
72
+ synthetic_name << engines_as_extensions
73
+
74
+ File.join(File.dirname(file), synthetic_name)
75
+ end
76
+ end
77
+
78
+ def engines_as_extensions
79
+ @engines_as_extensions ||= begin
80
+ engines = options[:engines] || [ ]
81
+ out = Array(engines).flatten.map do |component|
82
+ component = component.to_s
83
+ component = ".#{component}" unless component =~ /^\./
84
+ component
85
+ end.join(".")
86
+ ".#{out}".gsub(/\.\.+/, '.')
87
+ end
88
+ end
89
+
90
+ def process_with_processors(processors, context, data)
91
+ result = data
92
+
93
+ processors.each do |processor|
94
+ args = [ file ]
95
+ if processor == ::Tilt::ScssTemplate && (::Parcels::Sprockets.requires_explicit_load_paths_for_css_template?)
96
+ args = [ file, 1, { :load_paths => context.environment.paths } ]
97
+ end
98
+
99
+ template = processor.new(*args) { result }
100
+ result = template.render(context, {})
101
+ end
102
+
103
+ result
104
+ end
105
+ end
106
+ end
107
+ end
@@ -0,0 +1,16 @@
1
+ require 'active_support/core_ext/module/delegation'
2
+
3
+ module Parcels
4
+ class Index
5
+ def initialize(environment)
6
+ @environment = environment
7
+ end
8
+
9
+ delegate :root, :logical_path_for, :is_underneath_root?, :add_all_widgets_to!, :widget_class_from_file, :add_widget_tree!, :to => :environment
10
+
11
+ private
12
+ attr_reader :environment
13
+
14
+ delegate :sprockets_environment, :to => :environment
15
+ end
16
+ end
@@ -0,0 +1,23 @@
1
+ # See if we can load Rails -- but don't fail if we can't; we'll just use this to decide whether we should
2
+ # load the Rails extensions or not.
3
+ begin
4
+ gem 'rails'
5
+ rescue Gem::LoadError => le
6
+ # ok
7
+ end
8
+
9
+ begin
10
+ require 'rails'
11
+ rescue LoadError => le
12
+ # ok
13
+ end
14
+
15
+ if defined?(::Rails)
16
+ require 'parcels/rails/railtie'
17
+
18
+ begin
19
+ require 'sass-rails'
20
+ rescue LoadError => le
21
+ # ok
22
+ end
23
+ end
@@ -0,0 +1,16 @@
1
+ require "parcels"
2
+
3
+ module Parcels
4
+ module Rails
5
+ class Railtie < ::Rails::Railtie
6
+ initializer :parcels, :after => [ :append_assets_path, :finisher_hook ] do |app|
7
+ parcels = ::Rails.application.assets.parcels
8
+
9
+ ::ActionController::Base.view_paths.map(&:to_s).each do |view_path|
10
+ view_path = File.expand_path(view_path)
11
+ parcels.add_widget_tree!(view_path)
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,153 @@
1
+ require 'active_support'
2
+ require 'active_support/core_ext/string'
3
+
4
+ require "parcels/index"
5
+
6
+ module Parcels
7
+ module Sprockets
8
+ def self.sprockets_version_components
9
+ @sprockets_version_components ||= ::Sprockets::VERSION.split(".").map { |x| x.to_i }
10
+ end
11
+
12
+ def self.requires_explicit_load_paths_for_css_template?
13
+ sprockets_version_components[0] <= 2 && sprockets_version_components[1] < 11
14
+ end
15
+
16
+ def self.requires_fix_for_protected_methods_on_directive_processor?
17
+ RUBY_VERSION =~ /^2/ && sprockets_version_components[0] <= 2 && sprockets_version_components[1] < 11
18
+ end
19
+ end
20
+ end
21
+
22
+ ::Sprockets::Environment.class_eval do
23
+ def parcels
24
+ @parcels ||= ::Parcels::Environment.new(self)
25
+ end
26
+
27
+ def index_with_parcels
28
+ parcels.create_and_add_all_workaround_directories!
29
+ index_without_parcels
30
+ end
31
+
32
+ alias_method_chain :index, :parcels
33
+ end
34
+
35
+ ::Sprockets::Index.class_eval do
36
+ # Older versions of Sprockets don't actually hang on to the environment here.
37
+ def initialize_with_parcels(environment)
38
+ initialize_without_parcels(environment)
39
+ @environment ||= environment
40
+ end
41
+
42
+ alias_method_chain :initialize, :parcels
43
+
44
+ def parcels
45
+ @parcels ||= ::Parcels::Index.new(@environment.parcels)
46
+ end
47
+ end
48
+
49
+ ::Sprockets::DirectiveProcessor.class_eval do
50
+ def process_require_parcels_directive(*set_names)
51
+ set_names = set_names.map do |set_name|
52
+ set_name = set_name.to_s.strip
53
+ set_name = $1 if set_name =~ /,?(.*?),?$/i
54
+ set_name.strip.to_sym
55
+ end
56
+ context.environment.parcels.add_all_widgets_to!(context, set_names.map(&:to_sym))
57
+ end
58
+ end
59
+
60
+ ::Sprockets::AssetAttributes.class_eval do
61
+ def format_extension_with_parcels
62
+ out = format_extension_without_parcels
63
+ out = nil if out && out =~ /^\.html$/i
64
+ out
65
+ end
66
+
67
+ alias_method_chain :format_extension, :parcels
68
+ end
69
+
70
+ if ::Parcels::Sprockets.requires_fix_for_protected_methods_on_directive_processor?
71
+ ::Sprockets::DirectiveProcessor.class_eval do
72
+ instance_methods(true).select { |m| m =~ /^process_.*directive$/i }.each do |method_name|
73
+ public method_name
74
+ end
75
+ end
76
+ end
77
+
78
+ static_compiler_class = '::Sprockets::StaticCompiler'.constantize rescue nil
79
+ if static_compiler_class
80
+ instance_methods = static_compiler_class.instance_methods(true).map(&:to_s)
81
+ if instance_methods.include?('compile_path?')
82
+ static_compiler_class.class_eval do
83
+ def compile_path_with_parcels?(logical_path)
84
+ return false if ::Parcels.is_fortitude_logical_path?(logical_path)
85
+ compile_path_without_parcels?(logical_path)
86
+ end
87
+
88
+ alias_method_chain :compile_path?, :parcels
89
+ end
90
+ elsif instance_methods.include?('compile')
91
+ module ::Parcels::Sprockets
92
+ class StaticCompilerEnvProxy
93
+ def initialize(env)
94
+ @env = env
95
+ end
96
+
97
+ def each_logical_path(*args, &block)
98
+ @env.each_logical_path do |logical_path|
99
+ unless ::Parcels.is_fortitude_logical_path?(logical_path)
100
+ block.call(logical_path)
101
+ end
102
+ end
103
+ end
104
+
105
+ def method_missing(name, *args, &block)
106
+ @env.send(name, *args, &block)
107
+ end
108
+ end
109
+ end
110
+
111
+ static_compiler_class.class_eval do
112
+ def env
113
+ @_parcels_env_proxy ||= ::Parcels::Sprockets::StaticCompilerEnvProxy.new(@env)
114
+ end
115
+ end
116
+ end
117
+ end
118
+
119
+ begin
120
+ require 'sass/rails/importer'
121
+ rescue LoadError => le
122
+ # oh, well
123
+ end
124
+
125
+ [ '::Sprockets::SassImporter', '::Sass::Rails::Importer' ].each do |class_name|
126
+ klass = class_name.constantize rescue nil
127
+
128
+ if klass
129
+ klass.class_eval do
130
+ if defined?(klass::GLOB)
131
+ def find_relative_with_parcels(name, base, options)
132
+ parcels = context.environment.parcels
133
+ expanded_locations_to_search = context.environment.paths + [ File.dirname(base) ]
134
+
135
+ if name =~ self.class.const_get(:GLOB) && parcels.is_underneath_root?(base)
136
+ paths_to_search = expanded_locations_to_search
137
+
138
+ imports = nil
139
+ paths_to_search.each do |path_to_search|
140
+ glob_against = Pathname.new(File.join(path_to_search.to_s, 'dummy'))
141
+ imports = glob_imports(name, glob_against, :load_paths => [ path_to_search ])
142
+ return imports if imports
143
+ end
144
+ end
145
+
146
+ return find_relative_without_parcels(name, base, options.merge(:load_paths => expanded_locations_to_search))
147
+ end
148
+
149
+ alias_method_chain :find_relative, :parcels
150
+ end
151
+ end
152
+ end
153
+ end
@@ -0,0 +1,32 @@
1
+ module Parcels
2
+ module Utils
3
+ module PathUtils
4
+ class << self
5
+ def path_under(path, under_what)
6
+ path = path.to_s.strip
7
+ under_what = under_what.to_s.strip
8
+
9
+ if (path.length - under_what.length) > 1 && path[0..(under_what.length - 1)] == under_what &&
10
+ path[under_what.length..under_what.length] == File::SEPARATOR
11
+
12
+ path[(under_what.length + 1)..-1]
13
+ else
14
+ raise Errno::ENOENT, %{Path #{path.inspect} is not underneath directory #{under_what.inspect}.}
15
+ end
16
+ end
17
+
18
+ def widget_class_file_for_alongside_file(alongside_file)
19
+ directory = File.dirname(alongside_file)
20
+ basename = File.basename(alongside_file)
21
+ basename = $1 if basename =~ /^(.+?)\./
22
+
23
+ entries = Dir.entries(directory).select { |e| e =~ /^#{Regexp.escape(basename)}\./ && e =~ /\.rb$/i }
24
+ entries = entries.sort_by(&:length)
25
+ entry = entries[-1]
26
+
27
+ File.join(directory, entry) if entry
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,3 @@
1
+ module Parcels
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,158 @@
1
+ require 'active_support/core_ext/module/delegation'
2
+
3
+ require 'parcels/fortitude_inline_parcel'
4
+ require 'parcels/fortitude_alongside_parcel'
5
+ require 'parcels/dependency_parcel_list'
6
+
7
+ require 'find'
8
+
9
+ module Parcels
10
+ class WidgetTree
11
+ attr_reader :root, :parcels_environment
12
+
13
+ def initialize(parcels_environment, root)
14
+ @parcels_environment = parcels_environment
15
+ @root = File.expand_path(root, parcels_environment.root)
16
+
17
+ @sprockets_environments_added_to = { }
18
+ end
19
+
20
+ def add_workaround_directory_to_sprockets!(sprockets_environment)
21
+ return if (! root_exists?)
22
+
23
+ @sprockets_environments_added_to[sprockets_environment] ||= begin
24
+ ensure_workaround_directory_is_set_up!
25
+ sprockets_environment.prepend_path(workaround_directory)
26
+ true
27
+ end
28
+ end
29
+
30
+ def subpath_to(full_path)
31
+ ::Parcels::Utils::PathUtils.path_under(full_path, root)
32
+ end
33
+
34
+ def add_all_widgets_to_sprockets_context!(sprockets_context, set_names)
35
+ return unless root_exists?
36
+ sprockets_context.depend_on(root)
37
+
38
+ all_parcels = [ ]
39
+
40
+ Find.find(root) do |path|
41
+ full_path = File.expand_path(path, root)
42
+ stat = File.stat(full_path)
43
+
44
+ sprockets_context.depend_on(path) if stat.directory?
45
+ next unless stat.file?
46
+
47
+ extension = File.extname(full_path).strip.downcase
48
+ if (klass = EXTENSION_TO_PARCEL_CLASS_MAP[extension])
49
+ parcel = klass.new(self, full_path)
50
+ all_parcels << parcel if parcel.usable? && parcel.included_in_any_set?(set_names)
51
+ end
52
+ end
53
+
54
+ parcel_list = ::Parcels::DependencyParcelList.new
55
+ parcel_list.add_parcels!(all_parcels)
56
+ parcel_list.parcels_in_order.each do |parcel|
57
+ parcel.add_to_sprockets_context!(sprockets_context)
58
+ end
59
+ end
60
+
61
+ private
62
+ EXTENSION_TO_PARCEL_CLASS_MAP = {
63
+ '.rb'.freeze => ::Parcels::FortitudeInlineParcel,
64
+ '.pcss'.freeze => ::Parcels::FortitudeAlongsideParcel
65
+ }.freeze
66
+
67
+ ALL_EXTENSIONS = EXTENSION_TO_PARCEL_CLASS_MAP.keys.dup.freeze
68
+
69
+ PARCELS_WORKAROUND_DIRECTORY_NAME = ".parcels_sprockets_workaround".freeze
70
+
71
+ PARCELS_LOGICAL_PATH_PREFIXES = EXTENSION_TO_PARCEL_CLASS_MAP.values.map { |k| k.logical_path_prefix }
72
+
73
+ def root_exists?
74
+ File.exist?(root)
75
+ end
76
+
77
+ def workaround_directory
78
+ @workaround_directory ||= File.join(root, PARCELS_WORKAROUND_DIRECTORY_NAME)
79
+ end
80
+
81
+ def ensure_workaround_directory_is_set_up!
82
+ @workaround_directory_exists ||= begin
83
+ ensure_workaround_directory_exists!
84
+ ensure_nothing_else_is_in_workaround_directory!
85
+ ensure_symlinks_point_to_the_right_place!
86
+
87
+ true
88
+ end
89
+ end
90
+
91
+ def ensure_workaround_directory_exists!
92
+ unless File.directory?(workaround_directory)
93
+ if File.exist?(workaround_directory)
94
+ raise Errno::EEXIST, %{Parcels uses the directory '#{workaround_directory}' internally
95
+ (to allow us to safely add assets to Sprockets without treading on the global asset namespace);
96
+ however, there is already something at that path that is not a directory.}
97
+ end
98
+
99
+ FileUtils.mkdir_p(workaround_directory)
100
+ end
101
+ end
102
+
103
+ def ensure_nothing_else_is_in_workaround_directory!
104
+ entries = Dir.entries(workaround_directory).reject { |e| e =~ /^\./ }
105
+ extra = entries - PARCELS_LOGICAL_PATH_PREFIXES
106
+
107
+ if extra.length > 0
108
+ raise Errno::EEXIST, %{Parcels uses the directory '#{workaround_directory}' internally
109
+ (to allow us to safely add assets to Sprockets without treading on the global asset namespace);
110
+ it should either be empty, or contain at most symlinks named any of
111
+ #{PARCELS_LOGICAL_PATH_PREFIXES.map { |p| "'#{p}'" }.join(", ")}.
112
+ (Parcels will create those symlinks automatically; you should not manage them yourself.)
113
+
114
+ However, this directory currently contains other file(s) that we weren't expecting:
115
+
116
+ #{extra.join("\n")}}
117
+ end
118
+ end
119
+
120
+ SYMLINK_TARGET = "..".freeze
121
+
122
+ def ensure_symlinks_point_to_the_right_place!
123
+ PARCELS_LOGICAL_PATH_PREFIXES.each do |prefix|
124
+ symlink = File.join(workaround_directory, prefix)
125
+
126
+ if File.exist?(symlink)
127
+ if File.symlink?(symlink)
128
+ contents = File.readlink(symlink)
129
+
130
+ if contents == SYMLINK_TARGET
131
+ # ok, great
132
+ else
133
+ File.delete(symlink)
134
+ create_symlink!(prefix)
135
+ end
136
+ else
137
+ raise Errno::EEXIST, %{Parcels uses the directory '#{workaround_directory}' internally
138
+ (to allow us to safely add assets to Sprockets without treading on the global asset namespace);
139
+ it should either be empty, or contain at most symlinks named any of
140
+ #{PARCELS_LOGICAL_PATH_PREFIXES.map { |p| "'#{p}'" }.join(", ")}.
141
+
142
+ This directory has a file called '#{prefix}' that isn't a symlink.
143
+ Out of respect for your data, we're going to raise this fatal error. Please check what's going on,
144
+ and try again.}
145
+ end
146
+ else
147
+ create_symlink!(prefix)
148
+ end
149
+ end
150
+ end
151
+
152
+ def create_symlink!(prefix)
153
+ Dir.chdir(workaround_directory) do
154
+ FileUtils.ln_s(SYMLINK_TARGET, prefix)
155
+ end
156
+ end
157
+ end
158
+ end