wrap_it 0.2.0 → 1.0.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.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/.ruby-version +1 -0
  3. data/.yardopts +3 -0
  4. data/README.md +67 -66
  5. data/lib/wrap_it.rb +16 -16
  6. data/lib/wrap_it/arguments.rb +368 -0
  7. data/lib/wrap_it/base.rb +56 -47
  8. data/lib/wrap_it/callbacks.rb +24 -5
  9. data/lib/wrap_it/capture_array.rb +140 -0
  10. data/lib/wrap_it/container.rb +69 -25
  11. data/lib/wrap_it/derived_attributes.rb +22 -6
  12. data/lib/wrap_it/enums.rb +44 -34
  13. data/lib/wrap_it/frameworks.rb +7 -3
  14. data/lib/wrap_it/helpers.rb +66 -1
  15. data/lib/wrap_it/html.rb +149 -0
  16. data/lib/wrap_it/html_class.rb +164 -183
  17. data/lib/wrap_it/html_data.rb +28 -15
  18. data/lib/wrap_it/link.rb +40 -17
  19. data/lib/wrap_it/sections.rb +90 -2
  20. data/lib/wrap_it/switches.rb +33 -29
  21. data/lib/wrap_it/text_container.rb +83 -10
  22. data/lib/wrap_it/version.rb +2 -1
  23. data/spec/frameworks/log/development.log +2108 -0
  24. data/spec/integration/base_spec.rb +2 -2
  25. data/spec/integration/container_spec.rb +3 -3
  26. data/spec/integration/examples_spec.rb +16 -15
  27. data/spec/integration/text_container_spec.rb +3 -3
  28. data/spec/lib/arguments_array_spec.rb +37 -27
  29. data/spec/lib/arguments_spec.rb +153 -0
  30. data/spec/lib/base_spec.rb +2 -25
  31. data/spec/lib/callbacks_spec.rb +1 -1
  32. data/spec/lib/container_spec.rb +1 -1
  33. data/spec/lib/derived_attributes_spec.rb +1 -1
  34. data/spec/lib/enums_spec.rb +2 -3
  35. data/spec/lib/html_class_spec.rb +269 -80
  36. data/spec/lib/html_data_spec.rb +18 -12
  37. data/spec/lib/html_spec.rb +124 -0
  38. data/spec/lib/link_spec.rb +2 -2
  39. data/spec/lib/sections_spec.rb +1 -1
  40. data/spec/lib/switches_spec.rb +3 -3
  41. data/spec/lib/text_container_spec.rb +2 -2
  42. data/spec/support/example_groups/{wrap_it_example_group.rb → wrapped_example_group.rb} +5 -5
  43. data/wrap_it.gemspec +2 -0
  44. metadata +15 -8
  45. data/lib/wrap_it/arguments_array.rb +0 -128
  46. data/lib/wrap_it/module_helpers.rb +0 -23
@@ -5,33 +5,49 @@ module WrapIt
5
5
  # @author Alexey Ovchinnikov <alexiss@cybernetlab.ru>
6
6
  #
7
7
  module DerivedAttributes
8
+ # Documentation includes
9
+ # @!parse extend DerivedAttributes::ClassMethods
10
+
11
+ # module implementation
12
+
13
+ #
8
14
  def self.included(base)
9
15
  base.extend ClassMethods
10
16
  end
11
17
 
12
18
  #
13
- # Class methods to include
19
+ # {DerivedAttributes} class methods
14
20
  #
15
21
  module ClassMethods
22
+ #
23
+ # retrieves first founded derived variable or nil
24
+ # @param name [Symbol] variable name (should contain `@` sign)
25
+ #
26
+ # @return [Object, nil] founded variable or nil
16
27
  def get_derived(name)
17
28
  return instance_variable_get(name) if instance_variable_defined?(name)
18
29
  ancestors.each do |ancestor|
19
- break if ancestor == Object
20
30
  next unless ancestor.instance_variable_defined?(name)
31
+ break if ancestor == Base
21
32
  return ancestor.instance_variable_get(name)
22
33
  end
23
34
  nil
24
35
  end
25
36
 
37
+ #
38
+ # Collects all derived variables with specified name
39
+ # @param name [Symbol] variable name (should contain `@` sign)
40
+ # @param initial [Object] initial collection object
41
+ # @param method [Symbol] collection's method name to concatinate
42
+ # founded variable with collection
43
+ #
44
+ # @return [Object] collection of variables
26
45
  def collect_derived(name, initial = [], method = :concat)
27
46
  result = initial
28
- # if instance_variable_defined?(name)
29
- # result = result.send(method, instance_variable_get(name))
30
- # end
31
47
  ancestors.each do |ancestor|
32
- break if ancestor == Object
33
48
  next unless ancestor.instance_variable_defined?(name)
34
49
  result = result.send(method, ancestor.instance_variable_get(name))
50
+ break if ancestor == Base
35
51
  end
36
52
  result
37
53
  end
data/lib/wrap_it/enums.rb CHANGED
@@ -5,47 +5,38 @@ module WrapIt
5
5
  # @author Alexey Ovchinnikov <alexiss@cybernetlab.ru>
6
6
  #
7
7
  module Enums
8
+ # Documentation includes
9
+ # @!parse extend Enums::ClassMethods
10
+
11
+ # module implementation
12
+
8
13
  extend DerivedAttributes
9
14
 
15
+ #
10
16
  def self.included(base)
11
17
  base == Base || fail(
12
18
  TypeError,
13
19
  "#{self.class.name} can be included only into WrapIt::Base"
14
20
  )
15
- base.extend ClassMethods
16
- base.after_initialize :enums_init
17
- end
21
+ base.class_eval do
22
+ extend ClassMethods
18
23
 
19
- private
24
+ before_initialize { @enums = {} }
20
25
 
21
- def enums_init
22
- @enums = {}
23
- opt_keys = @options.keys
24
- enums.each do |name, opts|
25
- value = nil
26
- names = [name] + [opts[:aliases] || []].flatten
27
- opt_keys.select { |o| names.include? o }.each do |key|
28
- tmp = @options.delete(key)
29
- value ||= tmp
30
- !value.nil? && !opts[:values].include?(value) && value = nil
31
- end
32
- @arguments.extract!(Symbol, and: [opts[:values]]).each do |key|
33
- value ||= key
26
+ before_capture do
27
+ self.class.collect_derived(:@enums, {}, :merge).each do |name, e|
28
+ next unless e.key?(:default) && !@enums.key?(name)
29
+ send("#{name}=", e[:default])
30
+ end
34
31
  end
35
- send("#{name}=", value)
36
32
  end
37
33
  end
38
34
 
39
- def enums
40
- @enums_hash ||= self.class.collect_derived(:@enums, {}, :merge)
41
- end
42
-
43
35
  #
44
- # Class methods to include
36
+ # {Enums} class methods
45
37
  #
46
38
  module ClassMethods
47
39
  #
48
- # @dsl
49
40
  # Adds `enum`. When element created, creation arguments will be scanned
50
41
  # for `Symbol`, that included contains in `values`. If it founded, enum
51
42
  # takes this value. Also creation options inspected. If its contains
@@ -60,16 +51,26 @@ module WrapIt
60
51
  #
61
52
  # This method also adds getter and setter for this enum.
62
53
  #
54
+ # @example
55
+ # class Button < WrapIt::Base
56
+ # enum :style, %i(red green black), html_class_prefix: 'btn-'
57
+ # end
58
+ #
59
+ # btn = Button.new(template, :green)
60
+ # btn.render # => '<div class="btn-green">'
61
+ # btn = Button.new(template, style: :red)
62
+ # btn.render # => '<div class="btn-red">'
63
+ #
63
64
  # @param name [String, Symbol] Enum name. Converted to `Symbol`.
64
- # @param options [Hash] Enum options
65
- # @options options [String, Symbol] :html_class_prefix prefix of HTML
65
+ # @param opts [Hash] Enum options
66
+ # @option opts [String, Symbol] :html_class_prefix prefix of HTML
66
67
  # class that will automatically added to element if enum changes its
67
68
  # value.
68
- # @options options [Boolean] :html_class whether this enum changes
69
+ # @option opts [Boolean] :html_class whether this enum changes
69
70
  # should affect to html class.
70
- # @options options [Symbol, Array<Symbol>] :aliases list of enum aliases.
71
+ # @option opts [Symbol, Array<Symbol>] :aliases list of enum aliases.
71
72
  # Warning! Values are not converted - pass only `Symbols` here.
72
- # @options options [String, Symbol] :default default value for enum,
73
+ # @option opts [String, Symbol] :default default value for enum,
73
74
  # if nil or wrong value given. Converted to `Symbol`.
74
75
  # @yield [value] Runs block when enum value changed, gives it to block.
75
76
  # @yieldparam value [Symbol] New enum value.
@@ -90,25 +91,34 @@ module WrapIt
90
91
  opts[:regexp] = /\A#{prefix}(?:#{values.join('|')})\z/
91
92
  opts[:html_class_prefix] = prefix
92
93
  end
93
- define_method("#{name}") { @enums[name] }
94
+ define_method("#{name}") { @enums[name] ||= opts[:default] }
94
95
  define_method("#{name}=", &Enums.setter(name, &block))
95
96
  @enums ||= {}
97
+
98
+ o_params = {}
99
+ if opts.key?(:aliases)
100
+ aliases = [opts[:aliases]].flatten.compact
101
+ o_params[:if] = [name] + aliases
102
+ end
103
+
96
104
  @enums[name] = opts
105
+ option(name, **o_params) { |_, v| send("#{name}=", v) }
106
+ argument(name, if: Symbol, and: values) { |_, v| send("#{name}=", v) }
97
107
  end
98
108
  end
99
109
 
100
110
  private
101
111
 
102
112
  def self.setter(name, &block)
103
- proc do |value|
104
- opts = enums[name]
113
+ ->(value) do
114
+ opts = self.class.collect_derived(:@enums, {}, :merge)[name]
105
115
  v = value if opts[:values].include?(value)
106
116
  v ||= opts[:default] if opts.key?(:default)
107
117
  @enums[name] = v
108
118
  block.nil? || instance_exec(v, &block)
109
119
  if opts.key?(:regexp)
110
- remove_html_class(opts[:regexp])
111
- v.nil? || add_html_class("#{opts[:html_class_prefix]}#{v}")
120
+ html_class.delete(opts[:regexp])
121
+ v.nil? || html_class << "#{opts[:html_class_prefix]}#{v}"
112
122
  end
113
123
  end
114
124
  end
@@ -1,7 +1,9 @@
1
- #
2
- # Framework detection methods
3
- #
4
1
  module WrapIt
2
+ #
3
+ # Framework detection methods
4
+ #
5
+
6
+ # @private
5
7
  def self.framework
6
8
  return @framework unless @framework.nil?
7
9
  gems = Gem.loaded_specs.keys
@@ -14,10 +16,12 @@ module WrapIt
14
16
  end
15
17
  end
16
18
 
19
+ # @private
17
20
  def self.rails?
18
21
  framework == :rails
19
22
  end
20
23
 
24
+ # @private
21
25
  def self.sinatra?
22
26
  framework == :sinatra
23
27
  end
@@ -1,9 +1,64 @@
1
1
  #
2
- # Helper registering
2
+ # Registering helpers
3
+ #
4
+ # To use your classes and helpers in templates you should register your
5
+ # library. First, in your framework initialization, you should register
6
+ # your library in WrapIt. You can have separate module for it or WrapIt
7
+ # will make anonymous one. After this, your module will have `register`
8
+ # and `unregister` methods to register your classes.
9
+ #
10
+ # @example usual case - library in separate module
11
+ # # initialization time
12
+ # module Library
13
+ # module Helpers; end
14
+ # end
15
+ # WrapIt.register_module Library::Helpers, prefix: 'lib_'
16
+ #
17
+ # # controller
18
+ # class MyController < ApplicationController
19
+ # helper Library::Helpers
20
+ # end
21
+ #
22
+ # # implementation
23
+ # module Library
24
+ # module Helpers
25
+ # class Button < WrapIt::Base
26
+ # ...
27
+ # end
28
+ #
29
+ # register :super_button, Button
30
+ # end
31
+ # end
32
+ #
33
+ # # in template:
34
+ # <%= lib_super_button 'text' %>
35
+ #
36
+ # @example anonymous module
37
+ # helpers = WrapIt.register_module prefix: 'lib_'
38
+ #
39
+ # class Button < WrapIt::Base
40
+ # ...
41
+ # end
42
+ #
43
+ # helpers.register :super_button, Button
44
+ #
45
+ # class MyController
46
+ # helper helpers
47
+ # end
3
48
  #
4
49
  # @author Alexey Ovchinnikov <alexiss@cybernetlab.ru>
5
50
  #
6
51
  module WrapIt
52
+ #
53
+ # Registers helpers module
54
+ #
55
+ # @overload register_module(mod = nil, opts = {})
56
+ # @param mod [Module] module for register. Anonymous module will be
57
+ # created if ommited.
58
+ # @param opts [Hash] options
59
+ # @option opts [String] :prefix prefix for helper methods
60
+ #
61
+ # @return [void]
7
62
  def self.register_module(*args)
8
63
  options = args.extract_options!
9
64
  options.symbolize_keys!
@@ -17,6 +72,16 @@ module WrapIt
17
72
  mod
18
73
  end
19
74
 
75
+ # @!method register([name, ...], class_name)
76
+ # adds to template list of helpers for creating elements of specified class
77
+ # @param name [Symbol, String] name of helper. Will be prefixed with prefix
78
+ # option, specified in {WrapIt#register_module} call.
79
+ # @param class_name [String, Class] element class
80
+
81
+ # @!method unregister([name, ...])
82
+ # removes list of helpers from template
83
+ # @param name [Symbol, String] name of helper to remove from tampate
84
+
20
85
  private
21
86
 
22
87
  def self.register_block(options)
@@ -0,0 +1,149 @@
1
+ require File.join %w(wrap_it html_class)
2
+ require File.join %w(wrap_it html_data)
3
+
4
+ module WrapIt
5
+ #
6
+ # Methods for manipulationg with HTML class. For internal usage.
7
+ # You should not include this class directly - subclass from
8
+ # `WrapIt::Base` instead.
9
+ #
10
+ # @author Alexey Ovchinnikov <alexiss@cybernetlab.ru>
11
+ #
12
+ module HTML
13
+ # Documentation includes
14
+ # @!parse extend HTML::ClassMethods
15
+
16
+ # module implementation
17
+
18
+ extend DerivedAttributes
19
+
20
+ #
21
+ def self.included(base)
22
+ base == Base || fail(
23
+ TypeError,
24
+ "#{self.class.name} can be included only into WrapIt::Base"
25
+ )
26
+ base.class_eval do
27
+ extend ClassMethods
28
+
29
+ option(:class) { |_, v| self.html_class << v }
30
+
31
+ # TODO: extend hashes for html_attr and html_data
32
+ before_initialize do
33
+ html_class
34
+ @html_attr ||= {}
35
+ @html_data ||= {}
36
+ end
37
+ end
38
+ end
39
+
40
+ # TODO: actually we should have separate setter and merge (see Base)
41
+ #
42
+ # Sets HTML attributes hash.
43
+ #
44
+ # Actually it merges its with current
45
+ # attributes. To remove some attributes use `html_attr.delete(:attr)`.
46
+ # extracts HTML class and data from provided hash and places its to
47
+ # appropriate holder
48
+ #
49
+ # @param hash [Hash] attributes
50
+ #
51
+ # @return [Hash] resulting attributes
52
+ def html_attr=(hash)
53
+ return unless hash.is_a?(Hash)
54
+ hash.symbolize_keys!
55
+ html_class << hash.delete(:class)
56
+ html_data.merge(hash.delete(:data) || {})
57
+ (@html_attr ||= {}).merge!(hash)
58
+ end
59
+
60
+ #
61
+ # Retrieves HTML attributes hash (without HTML class and HTML data)
62
+ #
63
+ # @return [Hash] attributes
64
+ def html_attr
65
+ @html_attr ||= {}
66
+ end
67
+
68
+ #
69
+ # Retrieves HTML data hash
70
+ #
71
+ # @return [Hash] data
72
+ def html_data
73
+ @html_data ||= {}
74
+ end
75
+
76
+ #
77
+ # HTML class prefix getter
78
+ #
79
+ # This prefix used in enums to combine HTML classes.
80
+ #
81
+ # @return [String] HTML class prefix.
82
+ def html_class_prefix
83
+ @html_class_prefix ||= self.class.html_class_prefix
84
+ end
85
+
86
+ #
87
+ # Sets HTML class(es) for element
88
+ #
89
+ # @example
90
+ # element.html_class = [:a, 'b', ['c', :d, 'a']]
91
+ # element.html_class #=> ['a', 'b', 'c', 'd']
92
+ #
93
+ # @param value [Symbol, String, Array<Symbol, String>] HTML class or list
94
+ # of classes. All classes will be converted to Strings, duplicates are
95
+ # removed. Refer to {HTMLClass} description for details.
96
+ # @return [HTMLClass] resulting html class
97
+ def html_class=(value)
98
+ @html_class = HTMLClass.new(value)
99
+ end
100
+
101
+ #
102
+ # Retrieves HTML class of element
103
+ #
104
+ # See {HTMLClass} for details
105
+ #
106
+ # @return [HTMLClass] HTML class of element
107
+ def html_class
108
+ @html_class ||= HTMLClass.new
109
+ end
110
+
111
+ protected
112
+
113
+ def add_default_classes
114
+ html_class << self.class.collect_derived(
115
+ :@html_class, HTMLClass.new, :<<
116
+ )
117
+ end
118
+
119
+ #
120
+ # {HTML} class methods
121
+ #
122
+ module ClassMethods
123
+ #
124
+ # Adds default html classes, thats are automatically added when element
125
+ # created.
126
+ # @overload html_class([html_class, ...])
127
+ # @param html_class [String, Symbol, Array<String, Symbol>] HTML class.
128
+ # Converted to `String`
129
+ #
130
+ # @return [void]
131
+ def html_class(*args)
132
+ (@html_class ||= HTMLClass.new) << args
133
+ end
134
+
135
+ #
136
+ # Sets HTML class prefix. It used in switchers and enums
137
+ # @param prefix [String] HTML class prefix
138
+ #
139
+ # @return [void]
140
+ def html_class_prefix(prefix = nil)
141
+ return(get_derived(:@html_class_prefix) || '') if prefix.nil?
142
+ prefix.is_a?(Symbol) && prefix = prefix.to_s
143
+ prefix.is_a?(String) || fail(ArgumentError,
144
+ 'prefix should be a String or Symbol')
145
+ @html_class_prefix = prefix
146
+ end
147
+ end
148
+ end
149
+ end