├── .gitignore ├── .rspec ├── Gemfile ├── LICENSE.txt ├── README.md ├── Rakefile ├── css-class-string.gemspec ├── lib ├── css-class-string.rb ├── css_class_string.rb └── css_class_string │ ├── helper.rb │ ├── railtie.rb │ ├── version.rb │ └── view_helpers.rb ├── profiling └── benchmark.rb └── spec ├── css_class_string └── helper_spec.rb └── spec_helper.rb /.gitignore: -------------------------------------------------------------------------------- 1 | *.gem 2 | *.rbc 3 | .bundle 4 | .config 5 | .yardoc 6 | Gemfile.lock 7 | InstalledFiles 8 | _yardoc 9 | coverage 10 | doc/ 11 | lib/bundler/man 12 | pkg 13 | rdoc 14 | spec/reports 15 | test/tmp 16 | test/version_tmp 17 | tmp 18 | -------------------------------------------------------------------------------- /.rspec: -------------------------------------------------------------------------------- 1 | --color 2 | --warnings 3 | --require spec_helper 4 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | # Specify your gem's dependencies in css_class.gemspec 4 | gemspec 5 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014 Dmitriy Rozhkov 2 | 3 | MIT License 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | "Software"), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CssClassString 2 | 3 | Helper for creating css class strings inspired by ReactJS classSet 4 | 5 | - Pass bare arguments for default classes 6 | - Pass hash of `class => ` for conditional classes 7 | - Use array with two classes as a `key` and first will be used for truthy and second for falsey value `[:true?, :false?] => ` 8 | 9 | ## Installation 10 | 11 | Add this line to your application's Gemfile: 12 | 13 | gem 'css-class-string' 14 | 15 | ## Usage 16 | 17 | ```haml 18 | // @boolvalue = true 19 | %span{class: class_string({some: true, classy: false, [:truthy, :falsy] => @boolvalue})} 20 | // equal to 21 | %span{class: class_string('some', falsy: false, [:truthy, :falsy] => @boolvalue)} 22 | // => 23 | ``` 24 | 25 | ```html+erb 26 | 27 | 28 | 29 | 30 | 31 | ``` 32 | 33 | Outside a view 34 | 35 | ```ruby 36 | CssClassString::Helper.new({}).to_s 37 | ``` 38 | 39 | ## Contributing 40 | 41 | 1. Fork it 42 | 2. Create your feature branch (`git checkout -b my-new-feature`) 43 | 3. Commit your changes (`git commit -am 'Add some feature'`) 44 | 4. Push to the branch (`git push origin my-new-feature`) 45 | 5. Create new Pull Request 46 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require "bundler/gem_tasks" 2 | -------------------------------------------------------------------------------- /css-class-string.gemspec: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | lib = File.expand_path('../lib', __FILE__) 3 | $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) 4 | require 'css_class_string/version' 5 | 6 | Gem::Specification.new do |spec| 7 | spec.name = "css-class-string" 8 | spec.version = CssClassString::VERSION 9 | spec.authors = ["Dmitriy Rozhkov"] 10 | spec.email = ["rojkov.dmitry@gmail.com"] 11 | spec.description = %q{Helper for creating css class strings inspired by ReactJS classSet} 12 | spec.summary = %q{} 13 | spec.homepage = "https://github.com/nLight/css-class-string" 14 | spec.license = "MIT" 15 | 16 | spec.files = `git ls-files`.split($/) 17 | spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) } 18 | spec.test_files = spec.files.grep(%r{^(test|spec|features)/}) 19 | spec.require_paths = ["lib"] 20 | 21 | spec.add_development_dependency "bundler", "~> 1.3" 22 | spec.add_development_dependency "rspec" 23 | spec.add_development_dependency "rake" 24 | end 25 | -------------------------------------------------------------------------------- /lib/css-class-string.rb: -------------------------------------------------------------------------------- 1 | require 'css_class_string' 2 | -------------------------------------------------------------------------------- /lib/css_class_string.rb: -------------------------------------------------------------------------------- 1 | require 'css_class_string/version' 2 | require 'css_class_string/railtie' if defined?(Rails) 3 | -------------------------------------------------------------------------------- /lib/css_class_string/helper.rb: -------------------------------------------------------------------------------- 1 | module CssClassString 2 | class Helper 3 | def initialize(*args) 4 | options = args.last.is_a?(::Hash) ? args.pop : {} 5 | @class_hash = args.map {|class_name| { class_name => true }}.reduce({}, &:merge) 6 | @class_hash.merge!(options) 7 | end 8 | 9 | def to_s 10 | @class_hash.map { |((tc, fc), v)| v ? tc : fc }.compact.join(" ") 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /lib/css_class_string/railtie.rb: -------------------------------------------------------------------------------- 1 | require 'css_class_string/view_helpers' 2 | 3 | module CssClassString 4 | class Railtie < Rails::Railtie 5 | initializer "css_class_string.view_helpers" do 6 | ActionView::Base.send :include, ViewHelpers 7 | end 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /lib/css_class_string/version.rb: -------------------------------------------------------------------------------- 1 | module CssClassString 2 | VERSION = "0.1.1" 3 | end 4 | -------------------------------------------------------------------------------- /lib/css_class_string/view_helpers.rb: -------------------------------------------------------------------------------- 1 | require "css_class_string/helper" 2 | 3 | module CssClassString 4 | module ViewHelpers 5 | def class_string(*args) 6 | ::CssClassString::Helper.new(*args).to_s 7 | end 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /profiling/benchmark.rb: -------------------------------------------------------------------------------- 1 | require 'benchmark' 2 | require 'securerandom' 3 | require 'css_class_string/view_helpers' 4 | include CssClassString::ViewHelpers 5 | 6 | NUM_CALLS = 40_000 7 | 8 | def class_name 9 | SecureRandom.hex(4) 10 | end 11 | 12 | def true_or_false 13 | [true, false].sample 14 | end 15 | 16 | arrays = Enumerator.new { |y| y << [[class_name, class_name], true_or_false] } 17 | strings = Enumerator.new { |y| y << [class_name, true_or_false] } 18 | 19 | Benchmark.bm do |b| 20 | b.report("With 1 array and 1 string values") do 21 | NUM_CALLS.times do 22 | class_string(Hash[arrays.take(1) + strings.take(1)]) 23 | end 24 | end 25 | 26 | b.report("With 5 array and 5 string values") do 27 | NUM_CALLS.times do 28 | class_string(Hash[arrays.take(5) + strings.take(5)]) 29 | end 30 | end 31 | 32 | b.report("With 10 array values") do 33 | NUM_CALLS.times do 34 | class_string(Hash[arrays.take(10)]) 35 | end 36 | end 37 | 38 | b.report("With 10 string values") do 39 | NUM_CALLS.times do 40 | class_string(Hash[strings.take(10)]) 41 | end 42 | end 43 | end -------------------------------------------------------------------------------- /spec/css_class_string/helper_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | require 'css_class_string/view_helpers' 3 | 4 | describe "CssClassString::Helper" do 5 | describe ".to_s" do 6 | 7 | context "when a key's value is truthy" do 8 | let(:hash) { {truthy: true} } 9 | subject { CssClassString::Helper.new(hash).to_s } 10 | 11 | it { is_expected.to eq("truthy") } 12 | end 13 | 14 | context "when a key's value is falsy" do 15 | let(:hash) { {falsy: false} } 16 | subject { CssClassString::Helper.new(hash).to_s } 17 | 18 | it { is_expected.to eq("") } 19 | end 20 | 21 | context "when a key is an array of two elements" do 22 | 23 | context "when value is truthy" do 24 | let(:hash) { {[:truthy, :falsy] => true} } 25 | subject { CssClassString::Helper.new(hash).to_s } 26 | 27 | it { is_expected.to eq("truthy") } 28 | end 29 | 30 | context "when value is falsy" do 31 | let(:hash) { {[:truthy, :falsy] => false} } 32 | subject { CssClassString::Helper.new(hash).to_s } 33 | 34 | it { is_expected.to eq("falsy") } 35 | end 36 | 37 | end 38 | 39 | context 'when multiple keys are given' do 40 | 41 | let(:hash) { 42 | { 43 | [:arr_truthy, :arr_falsy] => false, 44 | :str_truthy => true, 45 | :str_falsy => false 46 | } 47 | } 48 | subject { CssClassString::Helper.new(hash).to_s } 49 | 50 | it { is_expected.to match(/^\w+ \w+$/) } 51 | it { is_expected.to include('arr_falsy', 'str_truthy') } 52 | it { is_expected.not_to include('arr_truthy', 'str_falsy') } 53 | 54 | end 55 | 56 | context 'with truthy arguments only' do 57 | subject { CssClassString::Helper.new('truthy_1', 'truthy_2').to_s } 58 | it { is_expected.to eq('truthy_1 truthy_2') } 59 | end 60 | 61 | context 'with mixed arguments' do 62 | subject { CssClassString::Helper.new('truthy_1', 'truthy_2', falsy: false, truthy_3: true).to_s } 63 | it { is_expected.to eq('truthy_1 truthy_2 truthy_3') } 64 | end 65 | 66 | end 67 | end 68 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | # This file was generated by the `rspec --init` command. Conventionally, all 2 | # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`. 3 | # The generated `.rspec` file contains `--require spec_helper` which will cause this 4 | # file to always be loaded, without a need to explicitly require it in any files. 5 | # 6 | # Given that it is always loaded, you are encouraged to keep this file as 7 | # light-weight as possible. Requiring heavyweight dependencies from this file 8 | # will add to the boot time of your test suite on EVERY test run, even for an 9 | # individual file that may not need all of that loaded. Instead, make a 10 | # separate helper file that requires this one and then use it only in the specs 11 | # that actually need it. 12 | # 13 | # The `.rspec` file also contains a few flags that are not defaults but that 14 | # users commonly want. 15 | # 16 | # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration 17 | RSpec.configure do |config| 18 | # The settings below are suggested to provide a good initial experience 19 | # with RSpec, but feel free to customize to your heart's content. 20 | =begin 21 | # These two settings work together to allow you to limit a spec run 22 | # to individual examples or groups you care about by tagging them with 23 | # `:focus` metadata. When nothing is tagged with `:focus`, all examples 24 | # get run. 25 | config.filter_run :focus 26 | config.run_all_when_everything_filtered = true 27 | 28 | # Many RSpec users commonly either run the entire suite or an individual 29 | # file, and it's useful to allow more verbose output when running an 30 | # individual spec file. 31 | if config.files_to_run.one? 32 | # Use the documentation formatter for detailed output, 33 | # unless a formatter has already been configured 34 | # (e.g. via a command-line flag). 35 | config.default_formatter = 'doc' 36 | end 37 | 38 | # Print the 10 slowest examples and example groups at the 39 | # end of the spec run, to help surface which specs are running 40 | # particularly slow. 41 | config.profile_examples = 10 42 | 43 | # Run specs in random order to surface order dependencies. If you find an 44 | # order dependency and want to debug it, you can fix the order by providing 45 | # the seed, which is printed after each run. 46 | # --seed 1234 47 | config.order = :random 48 | 49 | # Seed global randomization in this process using the `--seed` CLI option. 50 | # Setting this allows you to use `--seed` to deterministically reproduce 51 | # test failures related to randomization by passing the same `--seed` value 52 | # as the one that triggered the failure. 53 | Kernel.srand config.seed 54 | 55 | # rspec-expectations config goes here. You can use an alternate 56 | # assertion/expectation library such as wrong or the stdlib/minitest 57 | # assertions if you prefer. 58 | config.expect_with :rspec do |expectations| 59 | # Enable only the newer, non-monkey-patching expect syntax. 60 | # For more details, see: 61 | # - http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax 62 | expectations.syntax = :expect 63 | end 64 | 65 | # rspec-mocks config goes here. You can use an alternate test double 66 | # library (such as bogus or mocha) by changing the `mock_with` option here. 67 | config.mock_with :rspec do |mocks| 68 | # Enable only the newer, non-monkey-patching expect syntax. 69 | # For more details, see: 70 | # - http://teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/ 71 | mocks.syntax = :expect 72 | 73 | # Prevents you from mocking or stubbing a method that does not exist on 74 | # a real object. This is generally recommended. 75 | mocks.verify_partial_doubles = true 76 | end 77 | =end 78 | end 79 | --------------------------------------------------------------------------------